Skip to content
Snippets Groups Projects
Select Git revision
  • 13e5c526ab4de980107c57fc43e1bcf64c248a6c
  • master default protected
  • fix-words-ann
  • wccl-rules-migration
  • develop
5 results

wccl-run.py

Blame
  • valunifier_tei.py 24.95 KiB
    #-*- coding:utf-8 -*-
    
    import datetime
    
    from django.db.models import Count, Min, Max
    from lxml import etree
    from xml.sax.saxutils import escape
    
    from unifier.models import UnifiedFrame2SlowalFrameMapping, \
                               UnifiedFrameArgumentSlowalFrameMapping
    from connections.models import ArgumentConnection, ExampleConnection
    
    from common.management.commands.schema_packer import SchemaPacker
    
    from collections import defaultdict
    
    XML_NAMESPACE = 'http://www.w3.org/XML/1998/namespace'
    
    
    def createteixml(outpath, unified_frames):
        root = write_root()
        write_header(root)
        write_content(root, unified_frames)
        with open(outpath, 'wb') as output_file:
            root.getroottree().write(output_file,
                                     encoding='UTF-8',
                                     pretty_print=True,
                                     xml_declaration=True,
                                     doctype=u'<!DOCTYPE TEI SYSTEM "tei_all.dtd">')
    
    def write_root():
        root = etree.Element('TEI')
        root.attrib[etree.QName(XML_NAMESPACE, 'lang')] = u'pl'
        root.attrib['xmlns'] = u'http://www.tei-c.org/ns/1.0'
        return root
        
    def write_header(root, extensions_file=False):
        tei_header = etree.SubElement(root, 'teiHeader')    
        file_desc = etree.SubElement(tei_header, 'fileDesc')
        
        title_stmt = etree.SubElement(file_desc, 'titleStmt')
        title = etree.SubElement(title_stmt, 'title')
        title.text = u'ValUnifier (?)'
        
        publication_stmt = etree.SubElement(file_desc, 'publicationStmt')
        publisher = etree.SubElement(publication_stmt, 'publisher')
        publisher.text = u'Institute of Computer Science, Polish Academy of Sciences (IPI PAN)'
        
        date = etree.SubElement(publication_stmt, 'date')
        date.attrib['when'] = datetime.datetime.now().strftime('%Y-%m-%d')
        
        write_license_elem(publication_stmt)
        
        source_desc = etree.SubElement(file_desc, 'sourceDesc')
        p = etree.SubElement(source_desc, 'p')
        p.text = u'?'
    
    def write_license_elem(parent):
        availability = etree.SubElement(parent, 'availability')
        licence = etree.SubElement(availability, 'licence')
        licence.attrib['target'] = u'http://creativecommons.org/licenses/by-sa/4.0/'
        
        p = etree.SubElement(licence, 'p')
        p.text = u'(C) Copyright 2012–2018 by the Institute of Computer Science, Polish Academy of Sciences (IPI PAN)'
        
        p = etree.SubElement(licence, 'p')
        p.text = u'This work is distributed under a CC BY-SA license: http://creativecommons.org/licenses/by-sa/4.0/'
        
        p = etree.SubElement(licence, 'p')
        p.text = '?'
    
    def write_content(root, unified_frames):
        text = etree.SubElement(root, 'text')
        body = etree.SubElement(text, 'body')
        schemata = etree.SubElement(body, 'div')
        frames = etree.SubElement(body, 'div')
        used_schemata = SchemaPacker()
        write_unified_frames(frames, unified_frames, used_schemata)
        write_used_schemata(schemata, used_schemata)
    
    #=================== DIV -- SEMANTIC FRAMES ===================#
        
    def write_unified_frames(parent, unified_frames, used_schemata):
        frames_head = etree.SubElement(parent, 'head')
        frames_head.text = 'Semantic Frames'
    
        for unified_frame in unified_frames:
            write_unified_frame_entry(parent, unified_frame, used_schemata)
    
    def write_unified_frame_entry(parent, unified_frame, used_schemata):
        entry_xml_id = u'unif_%d-ent' % unified_frame.id
        entry = etree.SubElement(parent, 'entry')
        entry.attrib[etree.QName(XML_NAMESPACE, 'id')] = entry_xml_id
    
        write_unified_frame_definition(entry, unified_frame)
    
        write_status_info(entry, unified_frame)
        
        write_unified_frame(entry, unified_frame)
        
        write_unified_frames_realizations(entry, unified_frame, used_schemata)
    
    def write_unified_frame_definition(entry, unified_frame):
        definition = etree.SubElement(entry, 'def')
        definition.text = unified_frame.title
    
    def write_status_info(parent, unified_frame): 
        general_fs = etree.SubElement(parent, 'fs')
        general_fs.attrib['type'] = 'general_info'
        status_f =  etree.SubElement(general_fs, 'f')
        status_f.attrib['name'] = 'status'
        status_string = etree.SubElement(status_f, 'string')
        status_string.text = unified_frame.status
    
    #=================== FS TYPE = "FRAME" ===================#
        
    def write_unified_frame(parent, unified_frame):
        frame_xml_id = u'unif_%d-frm' % unified_frame.id
        
        frame_fs = etree.SubElement(parent, 'fs')
        frame_fs.attrib[etree.QName(XML_NAMESPACE, 'id')] = frame_xml_id
        frame_fs.attrib['type'] = 'frame'
        
        write_frame_arguments(frame_fs, unified_frame)
        
    def write_frame_arguments(parent, unified_frame): 
        arguments_f = etree.SubElement(parent, 'f')
        arguments_f.attrib['name'] = 'arguments'
        
        vColl = etree.SubElement(arguments_f, 'vColl')
        vColl.attrib['org'] = 'set'
        
        for arg in unified_frame.sorted_arguments():
            write_frame_argument(vColl, unified_frame, arg)
    
    def write_frame_argument(parent, frame, arg):
        arg_base_id = u'unif_%d' % frame.id
        arg_xml_id = arg_base_id + u'.%d-arg' % arg.id
        
        argument_fs = etree.SubElement(parent, 'fs')
        argument_fs.attrib[etree.QName(XML_NAMESPACE, 'id')] = arg_xml_id
        argument_fs.attrib['type'] = 'argument'
    
        write_roles(argument_fs, arg)
        write_selectional_preferences(argument_fs, arg, arg_base_id)
        
    def write_roles(parent, arg):
        if arg.role_type is not None:
            role_type_f = etree.SubElement(parent, 'f')
            role_type_f.attrib['name'] = 'role_type'
            role_type_symbol = etree.SubElement(role_type_f, 'symbol')
            role_type_symbol.attrib['value'] = arg.role_type.type
    
        role_f = etree.SubElement(parent, 'f')
        role_f.attrib['name'] = 'role'
        role_symbol = etree.SubElement(role_f, 'symbol')
        if arg.role is None:
            role_symbol.attrib['value'] = '/'.join([r.role.role for r in arg.proposed_roles.all()])
        else:
            role_symbol.attrib['value'] = arg.role.role.role
    
            if arg.role.attribute is not None and arg.role.sub_attribute is not None:
                attributes_f = etree.SubElement(parent, 'f')
                attributes_f.attrib['name'] = 'arributes'
                vColl = etree.SubElement(attributes_f, 'vColl')
                vColl.attrib['org'] = 'set'
                if arg.role.attribute is not None:
                    write_role_attribute(vColl, arg.role.attribute.attribute)        
                if arg.role.sub_attribute is not None:
                    write_role_attribute(vColl, arg.role.sub_attribute.sub_attribute)
    
    def write_role_attribute(parent, symbol):
        attribute_symbol = etree.SubElement(parent, 'symbol')
        attribute_symbol.attrib['value'] = symbol
                
    def write_selectional_preferences(parent, arg, arg_base_id):
        if len(arg.predefined.all()) > 0 or\
           len(arg.synsets.all()) > 0 or\
           len(arg.relations.all()) > 0:
            sel_prefs_f = etree.SubElement(parent, 'f')
            sel_prefs_f.attrib['name'] = 'sel_prefs'
        
            sel_prefs_groups_fs = etree.SubElement(sel_prefs_f, 'fs')
            sel_prefs_groups_fs.attrib['type'] = 'sel_prefs_groups'
            
            write_synsets_selprefs(sel_prefs_groups_fs, arg)
            write_predefined_selprefs(sel_prefs_groups_fs, arg)
            write_relation_selprefs(sel_prefs_groups_fs, arg, arg_base_id)
        
    def write_synsets_selprefs(parent, arg):
        synsets = arg.synsets.all()
        if len(synsets) > 0:
            synsets_f = etree.SubElement(parent, 'f')
            synsets_f.attrib['name'] = 'synsets'
            
            vColl = etree.SubElement(synsets_f, 'vColl')
            vColl.attrib['org'] = 'set'
            
            for synset in synsets:
                write_synset(vColl, synset)
                
    def write_synset(parent, synset):
        id_numeric = etree.SubElement(parent, 'numeric')
        id_numeric.attrib['value'] = str(synset.id)
                
    def write_predefined_selprefs(parent, arg):
        predefs = arg.predefined.all()
        if len(predefs) > 0:
            predefs_f = etree.SubElement(parent, 'f')
            predefs_f.attrib['name'] = 'predefs'
            
            vColl = etree.SubElement(predefs_f, 'vColl')
            vColl.attrib['org'] = 'set'
            
            for predef in predefs:
                write_predef(vColl, predef)
                
    def write_predef(parent, predef):
        name_symbol = etree.SubElement(parent, 'symbol')
        name_symbol.attrib['value'] = predef.name
        
    def write_relation_selprefs(parent, arg, arg_base_id):
        relations = arg.relations.all()
        if len(relations) > 0:
            relations_f = etree.SubElement(parent, 'f')
            relations_f.attrib['name'] = 'relations'
            
            vColl = etree.SubElement(relations_f, 'vColl')
            vColl.attrib['org'] = 'set'
            
            for relation in relations:
                write_relation(vColl, relation, arg_base_id)
                
    def write_relation(parent, relation, arg_base_id):
        relation_fs = etree.SubElement(parent, 'fs')
        relation_fs.attrib['type'] = 'relation'
        
        relation_f = etree.SubElement(relation_fs, 'f')
        relation_f.attrib['name'] = 'type'
        type_symbol = etree.SubElement(relation_f, 'symbol')
        type_symbol.attrib['value'] = relation.relation.key
        
        to_f = etree.SubElement(relation_fs, 'f')
        to_f.attrib['name'] = 'to'
        to_xml_link = '#%s.%d-arg' % (arg_base_id, relation.to.id)
        arg_link = etree.SubElement(to_f, 'fs')
        arg_link.attrib['sameAs'] = to_xml_link
        arg_link.attrib['type'] = 'argument'
    
    #=================== FS TYPE = "FRAME_REALIZATIONS" ===================#
        
    def write_unified_frames_realizations(entry, unified_frame, used_schemata):
        realizations_fs = etree.SubElement(entry, 'fs')
        realizations_fs.attrib['type'] = 'frame_realizations'
    
        realizations_f = etree.SubElement(realizations_fs, 'f')
        realizations_f.attrib['name'] = 'realizations'
    
        vColl = etree.SubElement(realizations_f, 'vColl')
        vColl.attrib['org'] = 'set'
        
        write_lexical_units_realizations(vColl, unified_frame, used_schemata)
    
    def write_lexical_units_realizations(parent, unified_frame, used_schemata):
        frames_mappings = UnifiedFrame2SlowalFrameMapping.objects.filter(unified_frame=unified_frame,\
                                                                         removed=False)
        
        lexical_units_sortable = {}
        lexical_unit_mapping = {}
        for mapping in frames_mappings:
            frame = mapping.slowal_frame
            for lexical_unit in frame.lexical_units.all():
                lexical_unit_mapping[lexical_unit] = mapping
                lexical_units_sortable[(lexical_unit.base, lexical_unit.sense)] = lexical_unit
    
        for signature in sorted(lexical_units_sortable.keys()):
            lexical_unit = lexical_units_sortable[signature]
            mapping = lexical_unit_mapping[lexical_unit]
            write_lexical_unit_realization(parent, unified_frame, lexical_unit, mapping, used_schemata)
            
    def write_lexical_unit_realization(parent, unified_frame, lexical_unit, mapping, used_schemata):
        lexical_unit_realizations_fs = etree.SubElement(parent, "fs")
        lexical_unit_realizations_fs.attrib['type'] = "lexical_unit_realizations"
    
        lexical_unit_f = etree.SubElement(lexical_unit_realizations_fs, "f")
        lexical_unit_f.attrib['name'] = 'lexical_unit'
        write_lexical_unit(lexical_unit_f, lexical_unit, mapping)
    
        syntactic_realizations_f = etree.SubElement(lexical_unit_realizations_fs, 'f')
        syntactic_realizations_f.attrib['name'] = 'syntactic_realizations'
    
        vColl = etree.SubElement(syntactic_realizations_f, 'vColl')
        vColl.attrib['org'] = 'set'
        write_alternations(vColl, unified_frame, lexical_unit, mapping, used_schemata)
    
    def write_lexical_unit(parent, lexical_unit, mapping):
        meaning_fs = etree.SubElement(parent, 'fs')
        meaning_fs.attrib['type'] = 'lexical_unit'
        
        name_f = etree.SubElement(meaning_fs, 'f')
        name_f.attrib['name'] = 'name'
        name_content = etree.SubElement(name_f, 'string')
        name_content.text = lexical_unit.base
        
        variant_f = etree.SubElement(meaning_fs, 'f')
        variant_f.attrib['name'] = 'variant'
        variant_string = etree.SubElement(variant_f, 'string')
        variant_string.text = lexical_unit.sense
    
        if lexical_unit.luid is not None:
            plwnluid_f = etree.SubElement(meaning_fs, 'f')
            plwnluid_f.attrib['name'] = 'plwnluid'
            plwnluid_numeric = etree.SubElement(plwnluid_f, 'numeric')
            plwnluid_numeric.attrib['value'] = str(lexical_unit.luid)
            
        if lexical_unit.synset is not None and lexical_unit.synset.id > 0:
            plwnsid_f = etree.SubElement(meaning_fs, 'f')
            plwnsid_f.attrib['name'] = 'plwnsid'
            plwnsid_numeric = etree.SubElement(plwnsid_f, 'numeric')
            plwnsid_numeric.attrib['value'] = str(lexical_unit.synset.id)
    
        slowal_frame = mapping.slowal_frame
        if slowal_frame.opinion is not None:
            opinion_f = etree.SubElement(meaning_fs, 'f')
            opinion_f.attrib['name'] = 'opinion'
            opinion_symbol = etree.SubElement(opinion_f, 'symbol')
            opinion_symbol.attrib['value'] = slowal_frame.opinion.key
            
    def write_alternations(parent, unified_frame, lexical_unit, mapping, used_schemata):
        alternations = prepare_alternations(lexical_unit, mapping, used_schemata)
        for key in sorted(alternations.keys()):
            alternation_fs = etree.SubElement(parent, 'fs')
            alternation_fs.attrib['type'] = 'aternation'
            connections_f = etree.SubElement(alternation_fs, 'f')
            connections_f.attrib['name'] = 'connections'
            vColl = etree.SubElement(connections_f, 'vColl')
            vColl.attrib['org'] = 'set'
            for argument, schema_hooks in alternations[key].items():
                connection_fs = etree.SubElement(vColl, 'fs')
                connection_fs.attrib['type'] = 'connection'
                argument_f = etree.SubElement(connection_fs, 'f')
                argument_f.attrib['name'] = 'argument'
                argument_fs = etree.SubElement(argument_f, 'fs')
                argument_fs.attrib['type'] = 'argument'
                argument_fs.attrib['sameAs'] = u'#unif_%d.%d-arg' % (unified_frame.id, argument.id)
                phrases_f = etree.SubElement(connection_fs, 'f')
                write_phrases_coll(phrases_f, schema_hooks, used_schemata)
    
    def prepare_alternations(lexical_unit, mapping, used_schemata):
        connections_info = analyse_connections(mapping)
        
        argument_mappings = UnifiedFrameArgumentSlowalFrameMapping.objects.filter(unified_frame_mapping = mapping)
        alternations = defaultdict(lambda: defaultdict(lambda: []))
        for argument_mapping in argument_mappings:
            uargument = argument_mapping.unified_agrument
            sargument = argument_mapping.slowal_agrument
    
            success = False
            try:
                argument_realization = ArgumentConnection.objects.get(argument = sargument)
                success = True
            except:
                print(sargument.id)
                
            if success:
                by_schema_realizations = argument_realization.schema_connections.all()
                for schema_hook in by_schema_realizations:
                    if valid_connection(lexical_unit, schema_hook, connections_info):
                        subentry = schema_hook.subentry
                        schema = schema_hook.schema
                        used_schemata.add(subentry, schema)
                        alternation = schema_hook.alternation
                        alternations[(subentry.id, schema.id, alternation)][uargument].append(schema_hook)
    
        return alternations
    
    def analyse_connections(mapping):
        sframe = mapping.slowal_frame
        lus = sframe.lexical_units.all()
        lu_schema_connections = defaultdict(lambda: set())
        connected_lu_count = defaultdict(lambda: 0)
        for lu in lus:
            examples = ExampleConnection.objects.filter(lexical_unit=lu)
            for example in examples:
                scs = example.schema_connections.all()
                if len(scs) > 0:
                    schema_hook = scs[0]
                    schema_id = (schema_hook.subentry.id, schema_hook.schema.id)
                    lu_schema_connections[lu].add(schema_id)
                    connected_lu_count[schema_id] += 1
        return (lu_schema_connections, connected_lu_count)
    
    def valid_connection(lexical_unit, schema_hook, connections_info):
        schema_id = (schema_hook.subentry.id, schema_hook.schema.id)
        lu_schema_connections, connected_lu_count = connections_info
        if schema_id in lu_schema_connections[lexical_unit]:
            return True
        if connected_lu_count[schema_id] == 0:
            in_lemma = False
            in_lemma |= (' się ' in lexical_unit.base)
            in_lemma |= (lexical_unit.base.endswith(' się'))
            in_schema = False
            in_schema |= (schema_hook.subentry.inherent_sie.name == 'true')
            for position in schema_hook.schema.positions.all():
                if position.phrases_count == 1:
                    phrase_type = position.phrase_types.all()[0].main_type 
                    in_schema |= (phrase_type == 'refl')
                    in_schema |= (phrase_type == 'recip')
            return (in_lemma == in_schema)
        return False
    
    def write_phrases_coll(parent, phrases_list, used_schemata):
        vColl = etree.SubElement(parent, 'vColl')
        vColl.attrib['org'] = 'set'
        for phrase in phrases_list:
            phrase_fs = etree.SubElement(vColl, 'fs')
            phrase_fs.attrib['type'] = 'phrase'
            subentry_id, schema_id = used_schemata.get_ids(phrase.subentry, phrase.schema)
            phrase_fs.attrib['sameAs'] = u'#unif_%d.%d.%d.%d-phr' %(subentry_id, schema_id, phrase.position.id, phrase.phrase_type.id)
            
        
    #=================== DIV -- SYNTACTIC SCHEMATA ===================#
    
    def write_used_schemata(parent, used_schemata):
        schemata_head = etree.SubElement(parent, 'head')
        schemata_head.text = 'Syntactic Schemata'
    
        for subentry_id in used_schemata.unique_schemas:
            for schema_id in used_schemata.unique_schemas[subentry_id]:
                subentry, schema = used_schemata.unique_schemas[subentry_id][schema_id]
                write_schema_entry(parent, subentry, subentry_id, schema, schema_id)
                
    
    def write_schema_entry(parent, subentry, subentry_id, schema, schema_id):
        entry_xml_id = u'unif_%d.%d-schent' %(subentry_id, schema_id)
        entry = etree.SubElement(parent, 'entry')
        entry.attrib[etree.QName(XML_NAMESPACE, 'id')] = entry_xml_id
    
        write_schema_definition(entry, subentry, subentry_id, schema, schema_id)
    
        write_schema(entry, subentry, subentry_id, schema, schema_id)
    
    def write_schema_definition(parent, subentry, subentry_id, schema, schema_id):
        d = etree.SubElement(parent, 'def')
        d.text = schema_textual_representation(subentry, schema)
    
    def schema_textual_representation(subentry, schema):
        result = ''
    
        if subentry.inherent_sie.name == 'true':
            result += ' się:'
        else:
            rerult += ':'
        
        opinion = schema.opinion.key
        if opinion == 'vul':
            result += ' wulgarny:'
        elif opinion == 'col':
            result += ' potoczny:'
        elif opinion == 'dat':
            result += ' archaiczny:'
        elif opinion == 'bad':
            result += ' zły:'
        elif opinion == 'unc':
            result += ' wątpliwy:'
        elif opinion == 'cer':
            result += ' pewny:'
        else:
            result += ' brak:'
    
        if subentry.negativity is not None:
            result += ' ' + subentry.negativity.name + ':'
        else:
            result += ' :'
    
        if subentry.predicativity.name == 'true':
            result += ' pred:'
        else:
            rerult += ':'
    
        if subentry.aspect is not None:
            result += ' ' + subentry.aspect.name + ':'
        else:
            result += ' :'
    
        positions_rep = []
        for position in schema.positions.all():
            positions_rep.append(str(position))
    
        result += ' ' + ' + '.join(positions_rep)
    
        return result
            
    def write_schema(parent, subentry, subentry_id, schema, schema_id):
        schema_xml_id = u'unif_%d.%d-sch' %(subentry_id, schema_id)
    
        schema_fs = etree.SubElement(parent, 'fs')
        schema_fs.attrib[etree.QName(XML_NAMESPACE, 'id')] = schema_xml_id
        schema_fs.attrib['type'] = 'schema'
    
        # textual representation @TODO -- not present in the database
        # text_rep_f_elem = etree.SubElement(schema_fs_elem, 'f')
        # text_rep_f_elem.attrib['name'] = 'text_rep'
        # text_rep_string = etree.SubElement(text_rep_f_elem, 'string')
        # text_rep = schema.get_position_spaced_text_rep()
        # if schema.characteristics.filter(type=u'ZWROTNOŚĆ', value__value=u'się').exists():
        #     text_rep = ' ' + text_rep
        # text_rep_string.text = lemma.entry_obj.name + text_rep.replace(':',': ')
    
        # schema opinion
        schema_opinion = schema.opinion.key
        if schema.opinion.key is None:
            schema_opinion = 'unk'
        opinion_f = etree.SubElement(schema_fs, 'f')
        opinion_f.attrib['name'] = 'opinion'
        opinion_symbol = etree.SubElement(opinion_f, 'symbol')
        opinion_symbol.attrib['value'] = schema_opinion
    
        # inherent "się"
        reflex = subentry.inherent_sie.name
        selfmark_f = etree.SubElement(schema_fs, 'f')
        selfmark_f.attrib['name'] = 'inherent_sie'
        selfmark_binary = etree.SubElement(selfmark_f, 'binary')
        selfmark_binary.attrib['value'] = reflex
        
        # aspect
        aspect_f = etree.SubElement(schema_fs, 'f')
        aspect_f.attrib['name'] = 'aspect'
        if subentry.aspect is not None and subentry.aspect.name != '':
            aspect_symbol = etree.SubElement(aspect_f, 'symbol')
            aspect_symbol.attrib['value'] = subentry.aspect.name
        
        # negativity
        negativity_f = etree.SubElement(schema_fs, 'f')
        negativity_f.attrib['name'] = 'negativity'
        if subentry.negativity is not None and subentry.negativity.name != '':
            negativity_symbol = etree.SubElement(negativity_f, 'symbol')
            negativity_symbol.attrib['value'] = subentry.negativity.name
        
        # predicativity
        predicativity = subentry.predicativity.name
        predicativity_f = etree.SubElement(schema_fs, 'f')
        predicativity_f.attrib['name'] = 'predicativity'
        predicativity_binary = etree.SubElement(predicativity_f, 'binary')
        predicativity_binary.attrib['value'] = predicativity
    
        # positions
        write_positions(schema_fs, subentry_id, schema, schema_id)
    
    def write_positions(parent, subentry_id, schema, schema_id):
        positions = schema.positions.all()
        positions_f = etree.SubElement(parent, 'f')
        positions_f.attrib['name'] = 'positions'
        vColl = etree.SubElement(positions_f, 'vColl')
        vColl.attrib['org'] = 'set'
        for position in positions:
            write_position(vColl, subentry_id, schema_id, position)
            
    def write_position(parent, subentry_id, schema_id, position):
        position_xml_id = u'unif_%d.%d.%d-psn' %(subentry_id, schema_id, position.id)
        position_fs = etree.SubElement(parent, 'fs')
        position_fs.attrib['type'] = 'position'
        position_fs.attrib[etree.QName(XML_NAMESPACE, 'id')] = position_xml_id
    
        text_rep_f = etree.SubElement(position_fs, 'f')
        text_rep_f.attrib['name'] = 'textual_representation'
        text_rep_string = etree.SubElement(text_rep_f, 'string')
        text_rep_string.text = str(position)
        
        write_function(position_fs, position)
        
        write_control(position_fs, position)
        
        write_phrases(position_fs, subentry_id, schema_id, position)
    
    def write_function(parent, position):
        function = position.function
        if function is not None:
            function_f = etree.SubElement(parent, 'f')
            function_f.attrib['name'] = 'function'
            function_symbol = etree.SubElement(function_f, 'symbol')
            function_symbol.attrib['value'] = function.name
        
    def write_control(parent, position):
        control = position.control
        pred_control = position.pred_control
        if control is not None or pred_control is not None:
            control_f = etree.SubElement(parent, 'f')
            control_f.attrib['name'] = 'control'
            vColl = etree.SubElement(control_f, 'vColl')
            vColl.attrib['org'] = 'set'
            if control is not None:
                control = control.name
                control_symbol = etree.SubElement(vColl, 'symbol')
                control_symbol.attrib['value'] = control
            if pred_control is not None:
                control = pred_control.name
                pred_control_symbol = etree.SubElement(vColl, 'symbol')
                pred_control_symbol.attrib['value'] = control
    
    def write_phrases(parent, subentry_id, schema_id, position):
        phrases = position.phrase_types.all()
        phrases_f = etree.SubElement(parent, 'f')
        phrases_f.attrib['name'] = 'phrases'
        vColl = etree.SubElement(phrases_f, 'vColl')
        vColl.attrib['org'] = 'set'
        for phrase in phrases:
            write_phrase(vColl, subentry_id, schema_id, position, phrase)
        
    def write_phrase(parent, subentry_id, schema_id, position, phrase):
        phrase_xml_id = u'unif_%d.%d.%d.%d-phr' %(subentry_id, schema_id, position.id, phrase.id)
        phrase_fs = etree.SubElement(parent, 'fs')
        phrase_fs.attrib[etree.QName(XML_NAMESPACE, 'id')] = phrase_xml_id
        phrase_fs.attrib['type'] = phrase.main_type.name
        # @TODO -- currently no expansions file
        # if phrase.realizations.exists() and write_expansions_id:
        #     write_expansions_link(phrase_fs_elem, phrase)
        write_phrase_textrep(phrase_fs, phrase)
                
    def write_phrase_textrep(parent, phrase):
        text_rep = phrase.text_rep
        textrep_f = etree.SubElement(parent, 'f')
        textrep_f.attrib['name'] = 'textual_representation'
        textrep_string = etree.SubElement(textrep_f, 'string')
        textrep_string.text = text_rep