Определите, находится ли файл в формате JSON или XML

Цель этой функции - определить, является ли report_input_file либо в формате JSON, либо в формате XML, вот что я придумал , просто хотите знать, является ли это лучшей практикой /питоническим способом достижения этого?

def parse_report_file(self, report_input_file):
    """ Checks if input report file is of type json or xml """
    parsed_report_file = None
    try:
        parsed_report_file = self._parse_json_file(report_input_file)
        self.is_json_report_file = True
    except Exception, e:
        parsed_report_file = self._parse_xml_file(report_input_file)
        self.is_json_report_file = False

    return parsed_report_file
8 голосов | спросил JonB 5 PM00000030000003431 2016, 15:49:34

3 ответа


3

Идите так, как вы это делали. Принимая более дешевый подход, например, тестирование первого (небезопасного) символа, может работать на входе, который всегда преуспевает при разборе. Но как только вы столкнетесь с недопустимым файлом, вы застряли. Вероятно, вы не получите правильные сообщения об ошибках.

Реализация парсера для XML и /или JSON с регулярным выражением не будет работать. У вас будет несколько краевых случаев, когда вы достигаете ложных срабатываний или ложных негативов (например, XML, распознаваемых как JSON и наоборот). Вы парсер будет не так эффективен, как библиотеки, которые вы используете для обработки этих форматов. Вы получите меньше производительности и больше ошибок. Просто не делай этого!

О руководстве по стилю стиля python, которое я не могу судить, поскольку я не гуру-питон.

ответил bash0r 6 AM00000040000004431 2016, 04:51:44
1

Как сказал Декстер, вы можете сохранить его простым и просто взглянуть на первого персонажа. Отказ от этого заключается в том, что он может вернуть «Is JSON», если он искажен XML и наоборот, поэтому, если вы захотите, вы можете вернуть один из трех вариантов. Поэтому немного расширить и дать вам что-то, на что можно опираться. Вы можете использовать регулярные выражения для соответствия первому и последнему символам (и строить отсюда для чего-либо между ними). ​​

import 're'

def parse_report_file(report_input_file):
    with open(report_input_file, 'r') as unknown_file:
        # Remove tabs, spaces, and new lines when reading
        data = re.sub(r'\s+', '', unknown_file.read())
        if (re.match(r'^<.+>$', data)):
            return 'Is XML'
        if (re.match(r'^({|[).+(}|])$', data)):
            return 'Is JSON'
        return 'Is INVALID'

Второе регулярное выражение не совпадает с теми же самыми открывающимися скобками с закрывающимися фигурками, чтобы вы могли это сделать. Вы также можете прочитать весь файл без удаления пробелов и затем игнорировать любое количество начальных и конечных пробелов при выполнении дополнительных совпадений регулярных выражений, но я сделал это таким образом для большей читаемости.

Во всяком случае, еще один пример. Определенно, не самый результативный, но показывая вам некоторые варианты.

ответил Nate 5 PM000000100000002031 2016, 22:30:20
1

Я предполагаю, что вы действительно хотите проверить, что это действительные документы xml или json (или ни один из них).

Я не вижу проблемы с вашей структурой метода, кроме catch Exception, который, вероятно, слишком общий. Вы либо хотите поймать что-то более конкретное, как ValueError или настраиваемая ошибка для ваших типов.

Я не являюсь поклонником других предложений, просто проверяя первый символ в файле и не использую регулярное выражение для удаления пробелов, а затем ищем несколько разных скобок. В стандартной библиотеке есть хорошие модули, которые будут анализировать JSON или XML и выполнять эту работу для вас, например json и ElementTree ,

Вот совместимая с python 2/3 версия того, как вы можете вместить эти модули в свой существующий класс.

Я сделал это довольно просто. Некоторые люди предпочитают не делать IO или медленные вещи в объекте __init__, но если ваш класс действительно является абстрактным представлением документа json /xml то это идеальная ситуация для использования @property для атрибутов только для getter и установить их в parse_report_file.

Для этого, конечно, нужны некоторые модульные тесты, но я сделал быстрый тест, добавив некоторые вещи в точку входа. Он ожидает 3 файла, вот содержимое, если вы хотите попробовать.

real.xml

<?xml version='1.0' encoding='utf-8' ?>

<root>
    <some-node thing='stuff'>some text</some-node>
</root>

real.json

{ 
    "key" : "value" 
}

blank.txt

This file is really empty but it could just be anything that is not valid xml or json.

код

 from __future__ import print_function
import xml.etree.cElementTree as ET
import json

class ReportDocument(object):
    """
    ReportDocument is an abstraction of a JSON, XML or neither file type.
    """
    def __init__(self, report_input_file=None, *args, **kwargs):
        self._is_json_report_file=False
        self._is_xml_report_file=False
        self._parsed_report_file=None
        if report_input_file is not None:
            self.parse_report_file(report_input_file)

    @property
    def is_json_report_file(self):
        return self._is_json_report_file

    @property
    def is_xml_report_file(self):
        return self._is_xml_report_file

    def _parse_json_file(self,report_input_file):
        """
        Given a text file, returns a JSON object or None
        """
        with open(report_input_file,'rb') as in_file:
            return json.load(in_file)

    def _parse_xml_file(self,report_input_file):
        """
        Given a text file, returns an XML element or None
        """
        with open(report_input_file,'rb') as in_file:
            return ET.parse(in_file)

    def parse_report_file(self, report_input_file):
        """ 
        Checks if input report file is of type json or xml 
        returns a json object or an xml element or None
        """
        try:
            self._parsed_report_file = self._parse_xml_file(report_input_file)
            self._is_xml_report_file = True
        except ET.ParseError:
            try:
                self._parsed_report_file = self._parse_json_file(report_input_file)
                self._is_json_report_file = True
            except ValueError: # or in Python3 the specific error json.decoder.JSONDecodeError
                pass


if __name__ == '__main__':
    files_to_test = ['real.xml', 'real.json', 'blank.txt']
    for file_type in files_to_test:
        test_class = ReportDocument(file_type)

        print("{file_type}: \n\t is_json:{is_json_report_file} \n\t is_xml:{is_xml_report_file}".format(
                file_type=file_type, 
                is_json_report_file=test_class.is_json_report_file,
                is_xml_report_file = test_class.is_xml_report_file)
                )
ответил Davos 23 PMpMon, 23 Apr 2018 17:11:32 +030011Monday 2018, 17:11:32

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132