Как выбрать объекты дерева lxml и объекты схемы lxml в двоичные файлы и загрузить их - PullRequest
0 голосов
/ 26 марта 2019

Я пытаюсь засечь (на самом деле с помощью укропа) объекты деревьев элементов lxml и объекты схемы lxml в двоичные файлы, а затем загрузить их с помощью укропа, чтобы мне не приходилось анализировать эти файлы каждый раз, когда я запускаю свой скрипт на python. Файлы схемы XSD являются статическими и никогда не меняются. Но я сталкиваюсь с типичной проблемой с pickle (или укропом), и это то, что она не вызывает функцию init , когда я читаю их обратно. Я просмотрел документацию по питону на укропе и прочитал довольно много программных постов о том, как выбирать экземпляры классов и загружать их обратно при вызове конструкторов, чтобы вы могли реально использовать их. Если бы кто-нибудь мог помочь мне здесь, я был бы признателен.

from lxml import etree as ET


        for file_type in self.xml_schemas.keys():
              if os.path.isfile(self.xml_schema_files[file_type].replace("xsd", "xso")) and os.path.isfile(self.xml_schema_files[file_type].replace("xsd", "xst")):

                 with open(self.xml_schema_files[file_type].replace("xsd", "xst"), 'rb') as tree_binary_object:
                      self.xsd_trees[file_type] = dill.load(tree_binary_object).__new__(tree_binary_object)

                 with open(self.xml_schema_files[file_type].replace("xsd", "xso"), 'rb') as schema_binary_object:
                      self.xml_schemas[file_type] = dill.load(schema_binary_object).__new__(schema_binary_object)

              else:

                 xsd_tree = ET.parse(self.xml_schema_files[file_type])

                 self.xsd_trees[file_type] = xsd_tree
                 self.xml_schemas[file_type] = ET.XMLSchema(xsd_tree)

                 with open(self.xml_schema_files[file_type].replace("xsd", "xst"), 'wb') as tree_binary_object:
                      dill.dump(self.xsd_trees[file_type], tree_binary_object)

                 **bold**with open(self.xml_schema_files[file_type].replace("xsd", "xso"), 'wb') as schema_binary_object:
                      dill.dump(self.xml_schemas[file_type], schema_binary_object)

Я использую словари xml_schemas [file_type], в которых есть строки, указывающие на файлы XSD, и, как вы можете видеть, я заменяю расширение xsd на xst для представления объектов маринованного дерева схемы XML, а xso для представления схемы XML объекты. Сначала я проверяю, существуют ли эти двоичные файлы. Я даже не уверен, нужно ли мне выбирать деревья определения схемы XML. Что мне действительно нужно, так это объект класса схемы XML, извлеченный из двоичного файла, а затем загруженный обратно и использованный так же, как любой другой объект схемы lxml для проверки файлов XML. Я полагаю, мне может понадобиться создать подкласс lxml.etree.XMLSchema, чтобы это работало. Если это так, может ли кто-нибудь предоставить мне пример кода? Любая помощь приветствуется. Спасибо!

UPDATE

Итак, мне удалось выбрать проанализированные объекты дерева определения XML-схемы. Этого может быть достаточно для ускорения загрузки данных в моем сценарии проверки XML. Итак, в ответ на комментарий с просьбой добавить больше кода, это в основном то, что я сейчас делаю в классе mt:

import os
import dill
import stat
import pprint
import sys
import string
import re
import copy
from lxml import etree as ET

from utilities import line_parser

class xml_processing_utilities:

      def __init__(self):

          self.xml_schemas_location = "/data/scratch/bbarrett/scripts/python/test_case_validation/develop/maestro_files/xml_schemas/"

          self.xml_schema_files = {}

          self.xml_schema_files["CA"] = self.xml_schemas_location + "maestro_test_case.xsd"
          self.xml_schema_files["TC"] = self.xml_schemas_location + "maestro_test_config.xsd"
          self.xml_schema_files["SN"] = self.xml_schemas_location + "maestro_scenario.xsd"
          self.xml_schema_files["NM"] = self.xml_schemas_location + "maestro_node_mapping.xsd"
          self.xml_schema_files["NC"] = self.xml_schemas_location + "maestro_node_config.xsd"

          self.xml_schemas = {}

          self.xml_schemas["CA"] = None
          self.xml_schemas["TC"] = None
          self.xml_schemas["SN"] = None
          self.xml_schemas["NM"] = None
          self.xml_schemas["NC"] = None

          self.xsd_trees = {}

          self.xsd_trees["CA"] = None
          self.xsd_trees["TC"] = None
          self.xsd_trees["SN"] = None
          self.xsd_trees["NM"] = None
          self.xsd_trees["NC"] = None

          self.get_xml_schemas()

      def initialize_xml_data(self, xml_file, file_type):

          if os.path.isfile(xml_file) and self.file_is_readable(xml_file, -1, ""):
             xml_file_lines = self.read_xml_file_lines(xml_file)
          else:
             return False

          if self.validate_maestro_file_type(file_type, xml_file) != True:
             self.PRINT_COLOR.red("Error: " + xml_file + " is not a valid test case " + file_type + " file. It is missing an opening MAESTRO or SimData XML element at the $
             return False

          passed_syntax_check = True
          line_parser.parser_error_log = []

          parser = line_parser.LineNumberingParser(recover=True)
          parser.feed_lines_last_index = len(xml_file_lines) - 1

          try:
            xml_tree = ET.fromstringlist(xml_file_lines, parser)
          except ET.XMLSyntaxError as lxml_exception:
            pass

          if len(parser.feed_error_log) > 0 or len(line_parser.parser_error_log) > 0:
             passed_syntax_check = False
             self.lxml_error_handler(line_parser.parser_error_log, parser.feed_error_log, file_type, xml_file_lines)

          if not passed_syntax_check:
             return False

          if passed_syntax_check:
             passed_schema_check = True

             schema_validation_errors = None

#############xsd_tree = ET.parse(self.xml_schema_files[file_type])
#############self.xml_schemas[file_type] = self.xsd_trees[file_type]
             xml_schema = ET.XMLSchema(self.xsd_trees[file_type])

             try:
               xml_schema.assertValid(xml_tree)
             except ET.DocumentInvalid as schema_validation_errors:
               pass

             if schema_validation_errors != None and hasattr(schema_validation_errors, 'error_log'):
                self.lxml_error_handler(None, schema_validation_errors.error_log, file_type, xml_file_lines)
                passed_schema_check = False

             if passed_schema_check != True:
                return False


      def get_xml_schemas(self):


          for file_type in self.xml_schema_files.keys():

              if os.path.isfile(self.xml_schema_files[file_type].replace("xsd", "xso")) and os.path.isfile(self.xml_schema_files[file_type].replace("xsd", "xst")):

                 with open(self.xml_schema_files[file_type].replace("xsd", "xst"), 'rb') as tree_binary_object:
                      self.xsd_trees[file_type] = dill.load(tree_binary_object)

#################with open(self.xml_schema_files[file_type].replace("xsd", "xso"), 'rb') as schema_binary_object:
######################self.xml_schemas[file_type] = dill.load(schema_binary_object).__init__(self.xsd_trees[file_type])

              else:

                 self.xsd_trees[file_type] = ET.parse(self.xml_schema_files[file_type])

                 with open(self.xml_schema_files[file_type].replace("xsd", "xst"), 'wb') as tree_binary_object:
                      dill.dump(self.xsd_trees[file_type], tree_binary_object)

#################self.xml_schemas[file_type] = ET.XMLSchema(self.xsd_trees[file_type])

#################with open(self.xml_schema_files[file_type].replace("xsd", "xso"), 'wb') as schema_binary_object:
######################dill.dump(self.xml_schemas[file_type], schema_binary_object)

Не беспокойтесь о line_parser. Это просто класс XMLParser, подкласс которого позволяет использовать метод feed в списке строк строк файла XML, чтобы получить номер строки, чтобы сообщить пользователям, в какой строке они имеют синтаксическую ошибку XML.

Как вы можете видеть, попытки выбора (укропа) объектов схемы lxml были закомментированы. Когда я пробовал скрипт с этими строками, все еще находящимися в коде, это сообщение об ошибке, выдаваемое разорванным интерпретатором Python:

  File "validate_test_case.py", line 174, in <module>
    if ca_file.endswith(".xml") and UTILS.initialize_xml_data(ca_file, "CA") != False:
  File "/data/scratch/bbarrett/scripts/python/test_case_validation/develop/utilities/xml_utilities.py", line 132, in initialize_xml_data
    self.xml_schemas[file_type].assertValid(xml_tree)
  File "src/lxml/etree.pyx", line 3525, in lxml.etree._Validator.assertValid
  File "src/lxml/xmlschema.pxi", line 111, in lxml.etree.XMLSchema.__call__

Итак, было бы неплохо понять, как получить этот объект схемы lxml также зарезанным. Еще раз спасибо всем, кто отвечает с некоторыми советами!

UPDATE

Мне только что пришло в голову, что при извлечении объектов дерева схемы XML, а затем их загрузке с помощью pickle может не быть большого преимущества в скорости. Я вижу, что мой сценарий на самом деле не быстрее, чем когда он строил деревья из файлов определения схемы при каждом запуске сценария. Если этот подход не увеличивает скорость загрузки XML-данных, может быть, у кого-то есть предложения по ускорению загрузки? Я имею в виду, файлы схемы XML не меняются. Может ли быть какой-то способ сохранить построенное дерево XML на диск и затем быстро загрузить его обратно в объект lxml etree после того, как дерево было записано в файл данных? Любые предложения будут оценены.

UPDATE

Я только что обнаружил логическую ошибку в моем коде. Он всегда строил дерево из-за того, что оставлял проверку для файлов .xso (объекта схемы XML), что является заброшенной попыткой выбрать объекты определения схемы lxml. Итак, код теперь такой, как показано ниже:


      def initialize_xml_data(self, xml_file, file_type):

          if os.path.isfile(xml_file) and self.file_is_readable(xml_file, -1, ""):
             xml_file_lines = self.read_xml_file_lines(xml_file)
          else:
             return False

          if self.validate_maestro_file_type(file_type, xml_file) != True:
             self.PRINT_COLOR.red("Error: " + xml_file + " is not a valid test case " + file_type + " file. It is missing an opening MAESTRO or SimData XML element at the $
             return False

          passed_syntax_check = True
          line_parser.parser_error_log = []

          parser = line_parser.LineNumberingParser(recover=True)
          parser.feed_lines_last_index = len(xml_file_lines) - 1

          try:
            xml_tree = ET.fromstringlist(xml_file_lines, parser)
          except ET.XMLSyntaxError as lxml_exception:
            pass

          if len(parser.feed_error_log) > 0 or len(line_parser.parser_error_log) > 0:
             passed_syntax_check = False
             self.lxml_error_handler(line_parser.parser_error_log, parser.feed_error_log, file_type, xml_file_lines)

          if not passed_syntax_check:
             return False

          if passed_syntax_check:
             passed_schema_check = True

             schema_validation_errors = None

#############xsd_tree = ET.parse(self.xml_schema_files[file_type])
#############self.xml_schemas[file_type] = self.xsd_trees[file_type]
             xml_schema = ET.XMLSchema(self.xsd_trees[file_type])

             try:
               xml_schema.assertValid(xml_tree)
             except ET.DocumentInvalid as schema_validation_errors:
               pass

             if schema_validation_errors != None and hasattr(schema_validation_errors, 'error_log'):
                self.lxml_error_handler(None, schema_validation_errors.error_log, file_type, xml_file_lines)
                passed_schema_check = False

             if passed_schema_check != True:
                return False


      def get_xml_schema_trees(self):

          for file_type in self.xml_schema_files.keys():

#############if os.path.isfile(self.xml_schema_files[file_type].replace("xsd", "xst")):

#############with open(self.xml_schema_files[file_type].replace("xsd", "xst"), 'rb') as tree_binary_object:
###################self.xsd_trees[file_type] = dill.load(tree_binary_object)

 ############with open(self.xml_schema_files[file_type].replace("xsd", "xso"), 'rb') as schema_binary_object:
 #################self.xml_schemas[file_type] = dill.load(schema_binary_object).__init__(self.xsd_trees[file_type])

##########else:

              self.xsd_trees[file_type] = ET.parse(self.xml_schema_files[file_type])

##########with open(self.xml_schema_files[file_type].replace("xsd", "xst"), 'wb') as tree_binary_object:
###################dill.dump(self.xsd_trees[file_type], tree_binary_object)

#####################self.xml_schemas[file_type] = ET.XMLSchema(self.xsd_trees[file_type])

#########with open(self.xml_schema_files[file_type].replace("xsd", "xso"), 'wb') as schema_binary_object:
##################dill.dump(self.xml_schemas[file_type], schema_binary_object)


Так что, в принципе, я даже не пытаюсь засолить. Можно также удалить функцию, чтобы попытаться травить. Если бы кто-нибудь мог помочь мне с обработкой этих объектов lxml, я был бы очень благодарен.

...