XmlHandler.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 import AuxFuns
00004 import roslib.message
00005 import xml.etree.ElementTree as ET
00006 import yaml
00007 import json
00008 
00009 from rospy_message_converter import message_converter
00010 from AuxFuns import our_raw_input
00011 from AuxFuns import message_raw_input
00012 
00013 def validator(tree):
00014     configuration = tree.getroot().find("config")
00015     if configuration == None:
00016         print "This config file lacks the config tag."
00017         return False
00018 
00019     buttonKeyDict = {}
00020     idMessagesDict = {}
00021     idTopicDict = {}
00022 
00023     ## We check that there are lists for buttons, messages and topics.
00024     buttons = configuration.find("buttons")
00025     if buttons == None:
00026         print "This config file lacks the buttons tag."
00027         return False
00028 
00029     messages = configuration.find("messages")
00030     if messages == None:
00031         print "This config file lacks the messages tag."
00032         return False
00033 
00034     topics = configuration.find("topics")
00035     if topics == None:
00036         print "This config file lacks the topics tag."
00037         return False
00038 
00039     ## And procceed to check the integrity of all of them.
00040     for message in messages:
00041         try:
00042             if not message.attrib["id"] in idMessagesDict:
00043                 idMessagesDict.setdefault(message.attrib["id"], 0)
00044             else:
00045                 raise ValueError('The message id "' + message.attrib["id"] + '" is repeated.')
00046         except ValueError as e:
00047             print e.message
00048             return False
00049 
00050         try:
00051             if roslib.message.get_message_class(message.find("type").text) == None:
00052                 raise ValueError('The type message is not a valid type')
00053             else:
00054                 the_message = roslib.message.get_message_class(message.find("type").text)
00055                 message_object = message_converter.convert_dictionary_to_ros_message(message.find("type").text,
00056                                                                                      json.loads(
00057                                                                                          message.find("content").text))
00058 
00059         except ValueError as e:
00060             print e.message
00061             return False
00062     for topic in topics:
00063         try:
00064             if not topic.attrib["id"] in idTopicDict:
00065                 idTopicDict.setdefault(topic.attrib["id"], 0)
00066             else:
00067                 raise ValueError('The topic id "' + topic.attrib["id"] + '" is repeated.')
00068         except ValueError as e:
00069             print e.message
00070             return False
00071 
00072     ## We finally check the integrity of the buttons, deciding if the messages sent are compatible
00073     ## with the receiving topic.
00074     for button in buttons:
00075         try:
00076             if not button.find("key").text.upper() in buttonKeyDict:
00077                 buttonKeyDict.setdefault(button.find("key").text.upper(), 0)
00078             else:
00079                 raise ValueError('The "' + button.find("key").text.upper() + '" key is repeated.')
00080         except ValueError as e:
00081             print e.message
00082             return False
00083         ## This part checks that the message type is compatible with the topic's expectations.
00084         ismessage = False
00085         istopic = False
00086         try:
00087             for message in messages:
00088                 if button.find("message").text == message.attrib["id"]:
00089                     ismessage = True
00090                     for topic in topics:
00091                         if button.find("topic").text == topic.attrib["id"]:
00092                             istopic = True
00093                             if not topic.find("msg_type").text == message.find("type").text:
00094                                 raise ValueError(
00095                                     'The message ' + message.attrib["id"] + ' is not compatible with the topic ' +
00096                                     topic.attrib["id"] + '\'s type.')
00097             if not ismessage or not istopic:
00098                 raise ValueError('The ' + button.find(
00099                     "key").text.upper() + ' key\'s associated message type is not compatible with it\'s associated topic.')
00100         except ValueError as e:
00101             print e.message
00102             return False
00103     return True
00104 
00105 def xml_validator(xml):
00106     '''
00107     :param xml: An XML file.
00108     :return Boolean: It's true if the XML file is a valid XML configuration file.
00109     :raises ValueError: It raises an exception if the XML file is not a valid configuration file.
00110     This function checks that the input XML file is a valid XML configuration file for tele-dir.
00111     If the file is not valid, then the program ends and raises an error.
00112     '''
00113 
00114     ## We first check if the XML file is a valid XML file.
00115     try:
00116         tree =  ET.parse(xml)
00117     except ET.ParseError:
00118         print xml+" is not a valid XML file."
00119         return False
00120 
00121     ## We then check that it has a configuration section.
00122     return validator(tree)
00123 
00124 
00125 def xmlCreator(xml_dir):
00126     '''
00127     :return None:
00128     This function starts a prompt in the terminal for the user to create a custom valid XML configuration file.
00129     It asks for several inputs for the user to fill with the information required to make the configuration that
00130     the user desires.
00131     '''
00132     master = ET.ElementTree()
00133     xml = ET.Element("xml")
00134     master._setroot(xml)
00135     description = ET.Element("description")
00136     config = ET.Element("config")
00137     messages = ET.Element("messages")
00138     buttons = ET.Element("buttons")
00139     topics = ET.Element("topics")
00140     print "Initializing controller configuration."
00141     file_name = raw_input("Input file name: ")
00142     while len(file_name) < 1:
00143         file_name = raw_input("Input file name: ")
00144     name = ET.Element("name")
00145     name.text = file_name
00146     robot_name = raw_input("Input target robot name: ")
00147     robot = ET.Element("target_robot")
00148     robot.text = robot_name
00149     config_version = ET.Element("config_version")
00150     config_version.text = "1.0"
00151     description.insert(0, name)
00152     description.insert(1, robot)
00153     description.insert(2, config_version)
00154     xml.insert(0, description)
00155     print "Initializing topics configuration. "
00156     i = 1
00157     while True:
00158         topic = newTopic(i)
00159         topics.insert(i - 1, topic)
00160         i += 1
00161         end = our_raw_input("Do you wish to add another topic? (Y/N)", 'Y', 'N')
00162         if end.upper() == 'N':
00163             break
00164     i = 1
00165     print "Initializing messages configuration. "
00166     while True:
00167         message = newMessage(i)
00168         messages.insert(i - 1, message)
00169         i += 1
00170         end = our_raw_input("Do you wish to add another message? (Y/N)", 'Y', 'N')
00171         if end.upper() == 'N':
00172             break
00173     i = 1
00174     print "Initializing keyboard configuration. "
00175     while True:
00176 
00177         button = newButton(i, topics, messages)
00178         buttons.insert(i - 1, button)
00179         i += 1
00180         end = our_raw_input("Do you wish to add another button? (Y/N)", 'Y', 'N')
00181         if end.upper() == 'N':
00182             break
00183     config.insert(1, messages)
00184     config.insert(2, topics)
00185     config.insert(3, buttons)
00186     xml.insert(1, config)
00187     master.write(xml_dir + file_name + ".xml")
00188     print "File Created with name :" + file_name + ".xml!"
00189 
00190 
00191 def delete_key_by_topic(topic, buttons):
00192     list = []
00193     for button in buttons:
00194         if button.find("topic").text == topic.attrib['id']:
00195             list.append(button)
00196             buttons.remove(button)
00197     if len(list) > 0:
00198         print "The following buttons have been deleted: ",
00199         for button in list:
00200             print button.find("key").text + " ",
00201         print ".\n"
00202     else :
00203         print "No key has been deleted due to topic removal."
00204     return list
00205 
00206 
00207 def delete_key_by_message(message, buttons):
00208     list = []
00209     for button in buttons:
00210         if button.find("message").text == message.attrib['id']:
00211             list.append(button)
00212             buttons.remove(button)
00213     if len(list) > 0:
00214         print "The following buttons have been deleted: ",
00215         for button in list:
00216             print button.find("key").text + " ",
00217         print ".\n"
00218     else:
00219         print "No key has been deleted due to message removal."
00220     return list
00221 
00222 
00223 def newMessage(i):
00224     message_description = raw_input("Input message description: ")
00225     message_type = message_raw_input("Input message type: ")
00226     message_class = roslib.message.get_message_class(message_type)
00227     message_body = message_converter.convert_ros_message_to_dictionary(eval("message_class()"))
00228     message_content = json.dumps(AuxFuns.message_param_editor(message_body), sort_keys=True)
00229     return createMessage(i, message_description, message_type, message_content)
00230 
00231 
00232 def createMessage(i, message_description, message_type, message_content):
00233     content = ET.Element("content")
00234     content.text = message_content
00235     message = ET.Element("message", {'id': str(i)})
00236     description = ET.Element("description")
00237     description.text = message_description
00238     type = ET.Element("type")
00239     type.text = message_type
00240     message.insert(0, description)
00241     message.insert(1, type)
00242     message.insert(2, content)
00243     return message
00244 
00245 def newTopic(i):
00246     topic_name = raw_input("Input topic name: ")
00247     topic_msg = message_raw_input("Input topic msg_type: ")
00248     return createTopic(i, topic_name, topic_msg)
00249 
00250 def createTopic(i, topic_name, topic_msg):
00251     topic = ET.Element("topic", {'id': str(i)})
00252     name = ET.Element("name")
00253     name.text = topic_name
00254     msg_type = ET.Element("msg_type")
00255     msg_type.text = topic_msg
00256     topic.insert(0, name)
00257     topic.insert(1, msg_type)
00258     return topic
00259 
00260 def newButton(i, topics, messages):
00261     button_key = raw_input("Input only one key: ")
00262     while len(button_key) > 1:
00263         button_key = raw_input("Error Length " + str(len(button_key)) + ".Input only one key:")
00264     message_asociated = None
00265     while message_asociated == None:
00266         button_messages = raw_input("Input number of message associated: ")
00267         for message in messages:
00268             if button_messages == message.attrib['id']:
00269                 message_asociated = message
00270         if message_asociated == None:
00271             print "Error, the message wasn't found"
00272     topic_associated = None
00273     while topic_associated == None:
00274         button_topics = raw_input("Input topic associated: ")
00275         if len(topics.findall("topic")) < 1:
00276             raise ValueError("Topics is empty. Can't associate with a message")
00277         for topic in topics:
00278             if button_topics == topic.attrib['id']:
00279                 topic_associated = topic
00280         if topic_associated!= None:
00281             if message_asociated.find("type").text != topic_associated.find("msg_type").text:
00282                 print "Error message type in the topic selected (" + topic_associated.find("msg_type").text + ") , " \
00283                       "isn't the same that the message type selected (" + message_asociated.find("type").text +")."
00284                 topic_associated = None
00285         else:
00286             print "Topic with number " + button_topics + " don't exist. The existing topics are :",
00287             for topic in topics:
00288                 print " " + topic.attrib['id'],
00289             print "\n"
00290     key = ET.Element("key")
00291     message = ET.Element("message")
00292     topic = ET.Element("topic")
00293     key.text = button_key.upper()
00294     message.text = button_messages
00295     topic.text = button_topics
00296     button = ET.Element("button")
00297     button.insert(0, key)
00298     button.insert(1, message)
00299     button.insert(2, topic)
00300     return button
00301 
00302 def xmlEditor(xmlUrl, xml):
00303     '''
00304     :param xml: A valid tele-dir XML configuration file.
00305     :return None:
00306     This function prompts the user for changes in the xml XML file. It's designed to further improve the customization options for the user.
00307     '''
00308     #TODO all this shit
00309 
00310     try:
00311         tree =  ET.parse(xmlUrl+xml)
00312     except ET.ParseError:
00313         print xml+" is not a valid XML file."
00314         return False
00315 
00316 
00317     edited = False
00318     print "Welcome to the tele-dir configuration editor."
00319     descr_edit = our_raw_input("Do you wish to edit the description? (Y/N)", 'Y', 'N')
00320     if descr_edit.upper() == 'Y':
00321         description = tree.getroot().find("description")
00322         name = description.find("name")
00323         target_robot = description.find("target_robot")
00324         print   "The current name for this configuration is '"+name.text+"'" \
00325                 "And the target robot is '"+target_robot.text+"'."
00326         edit = our_raw_input("Input N to edit the name\n"
00327                             "      R to edit the target robot\n"
00328                             "      F to forget about editing the description and move forward\n", 'R', 'F', 'N')
00329         if edit.upper() == 'N':
00330             new_name = raw_input("Input new name: ")
00331             name.text = new_name
00332             edit = our_raw_input("Do yo wish to edit the target robot? (Y/N)", 'Y', 'N')
00333         if edit.upper() == 'R' or edit.upper() == 'Y':
00334             new_target_robot = raw_input("Input new target robot: ")
00335             target_robot.text = new_target_robot
00336 
00337     conf_edit = our_raw_input("Do you wish to edit the configuration? (Y/N)", 'Y', 'N')
00338     if conf_edit.upper() == 'Y':
00339         configuration = tree.getroot().find("config")
00340         while True:
00341 
00342             buttons = configuration.find("buttons")
00343             messages = configuration.find("messages")
00344             topics = configuration.find("topics")
00345             edit = our_raw_input("Input T to edit topics\n"
00346                              "      M to edit messages\n"
00347                          "      B to edit buttons\n", 'T', 'M', 'B').upper()
00348             if edit == 'T':
00349                 topic_bool = our_raw_input("Do you wish yo Add or Modify topics? (A/M)", 'A', 'M').upper()
00350                 if topic_bool == 'M':
00351                     for topic in topics:
00352                         print "The topic number "+topic.attrib['id']+" is: "
00353                         print ET.dump(topic)
00354                         option = our_raw_input("Input E to edit the topic \n"
00355                                               "      D to delete the topic \n"
00356                                               "      C to continue to the next topic.\n", 'E', 'D', 'C').upper()
00357                         if option == 'E':
00358                             topic.find("name").text = raw_input("Input topic name: ") or topic.find("name").text
00359                             topic.find("msg_type").text = message_raw_input("Input message type: ")
00360                         elif option == 'D':
00361                             if our_raw_input("Are you sure? (Y/N)", 'Y', 'N').upper() == 'Y':
00362                                 delete_key_by_topic(topic, buttons)
00363                                 topics.remove(topic)
00364                 elif topic_bool == 'A':
00365                     while True:
00366                         i = int(topics.findall('topic')[len(topics.findall('topic'))-1].attrib['id'])+1
00367                         topic = newTopic(i)
00368                         topics.insert(i - 1, topic)
00369                         end = our_raw_input("Do you wish to add another topic? (Y/N)", 'Y', 'N')
00370                         if end.upper() == 'N':
00371                             break
00372             elif edit == 'M':
00373                 mess_bool = our_raw_input("Do you wish yo Add or Modify messages? (A/M)", 'A', 'M').upper()
00374                 if mess_bool == 'M':
00375                     for message in messages:
00376                         print "The message with id "+message.attrib['id']+" is: "
00377                         print ET.dump(message)
00378                         option = our_raw_input("Input E to edit the message \n"
00379                                               "      D to delete the message \n"
00380                                               "      C to continue to the next message.\n", 'E', 'D', 'C').upper()
00381                         if option == 'E':
00382                             message.find("description").text = raw_input("Input message description: ") or message.find("description").text
00383                             type = message_raw_input("Input message type: ")
00384                             if message.find("type").text == type:
00385                                 message.find("content").text = json.dumps(AuxFuns.message_param_editor(json.loads(message.find("content").text)),sort_keys=True)
00386                             else:
00387                                 message_class = roslib.message.get_message_class(type)
00388                                 message_body = message_converter.convert_ros_message_to_dictionary(eval("message_class()"))
00389                                 message.find("content").text = json.dumps(AuxFuns.message_param_editor(message_body),sort_keys=True)
00390                         elif option == 'D':
00391                             if our_raw_input("Are you sure? (Y/N)", 'Y', 'N').upper() == 'Y':
00392                                 delete_key_by_message(message, buttons)
00393                                 messages.remove(message)
00394 
00395                 elif mess_bool == 'A':
00396                     while True:
00397                         i = int(messages.findall('message')[len(messages.findall('message'))-1].attrib['id'])+1
00398                         message = newMessage(i)
00399                         messages.insert(i - 1, message)
00400                         end = our_raw_input("Do you wish to add another message? (Y/N)", 'Y', 'N')
00401                         if end.upper() == 'N':
00402                             break
00403             elif edit == 'B':
00404                 butt_bool = our_raw_input("Do you wish yo Add or Modify buttons? (A/M)", 'A', 'M').upper()
00405                 if butt_bool == 'M':
00406                     i = 0
00407                     for button in buttons:
00408                         print "The button number "+i+" is: "
00409                         print ET.dump(button)
00410                         i+=1
00411                         option = our_raw_input("Input E to edit the button \n"
00412                                               "      D to delete the button \n"
00413                                               "      C to continue to the next button.\n", 'E', 'D', 'C').upper()
00414                         if option == 'E':
00415                             button_key = raw_input("Input button key") or button.find("key").text
00416                             while len(button_key) > 1:
00417                                 button_key = raw_input("Error Length " + str(len(button_key)) + ".Input only one key:")or button.find("key").text
00418                             message_asociated = None
00419                             while message_asociated == None:
00420                                 button_messages = raw_input("Input number of message associated: ") or button.find("message").text
00421                                 for message in messages:
00422                                     if button_messages == message.attrib['id']:
00423                                         message_asociated = message
00424                                 if message_asociated == None:
00425                                     print "Error, the message wasn't found"
00426                             topic_associated = None
00427                             while topic_associated == None:
00428                                 button_topics = raw_input("Input topic associated: ") or button.find("topic").text
00429                                 for topic in topics:
00430                                     if button_topics == topic.attrib['id']:
00431                                         topic_associated = topic
00432                                 if message_asociated.find("type").text != topic_associated.find("msg_type").text:
00433                                     print "Error message type in the topic selected, isn't the same that the message type selected."
00434                                     topic_associated = None
00435                             ## TODO: add a prompt to confirm the message/topic selections, displaying said messages and or topics
00436                             button.find("topic").text = button_topics
00437                             button.find("key").text = button_key
00438                             button.find("message").text = button_messages
00439                         elif option == 'D':
00440                             if our_raw_input("Are you sure? (Y/N)", 'Y', 'N').upper() == 'Y':
00441                                 buttons.remove(button)
00442                 elif butt_bool == 'A':
00443                     while True:
00444                         try:
00445                             i = len(buttons.findall('button'))+1
00446                             button = newButton(i, topics, messages)
00447                             buttons.insert(i - 1, button)
00448                             end = our_raw_input("Do you wish to add another button? (Y/N)", 'Y', 'N')
00449                             if end.upper() == 'N':
00450                                 break
00451                         except ValueError as e :
00452                             print e.message
00453                             break
00454 
00455             if our_raw_input("Do you wish continue editing? (Y/N)", 'Y', 'N').upper() == 'N':
00456                 break
00457 
00458     file = raw_input("Enter the new file name: ")
00459     file_name = xmlUrl + file + ".xml"
00460     if (file== ""):
00461         file_name = xmlUrl + xml
00462     tree.write(file_name )
00463     print "The file has been saved with name "+ file_name
00464 
00465 
00466 
00467 
00468 
00469 


tele_dir
Author(s): Rodrigo Delgado , Steffan Wiche
autogenerated on Thu Jun 6 2019 17:32:56