Python Forum

Full Version: XML for EPP formatting
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi,

I am trying to work with the epp-python-client which is available on Github, but creating a contact is driving me nuts because I doesn't want to work. I feel there is an issue with the epp-python-client, but I contacted the developer and he doesn't seem to find what the issue is either.

I am using a standard EPP server connection. They all comply with a standard for EPP, so they should be compatible with each other. So I hope that there is someone with a working example that could solve this mystery.

The EPP XML for creating a domain contact looks like this (this is the standard XML input the EPP server expects):
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="urn:ietf:params:xml:ns:epp-1.0 epp-1.0.xsd">
 <command>
   <create>
     <contact:create
      xmlns:contact="urn:ietf:params:xml:ns:contact-1.0"
      xsi:schemaLocation="urn:ietf:params:xml:ns:contact-1.0
      contact-1.0.xsd">
       <contact:id>sh8013</contact:id>
       <contact:postalInfo type="int">
         <contact:name>John Doe</contact:name>
         <contact:org>Example Inc.</contact:org>
         <contact:addr>
           <contact:street>123 Example Dr.</contact:street>
           <contact:street>Suite 100</contact:street>
           <contact:city>Dulles</contact:city>
           <contact:sp>VA</contact:sp>
           <contact:pc>20166-6503</contact:pc>
           <contact:cc>US</contact:cc>
         </contact:addr>
       </contact:postalInfo>
       <contact:voice>+1.7035555555</contact:voice>
       <contact:fax>+1.7035555556</contact:fax>
       <contact:email>[email protected]</contact:email>
       <contact:authInfo>
         <contact:pw/>
       </contact:authInfo>
     </contact:create>
   </create>
   <clTRID>30FC8ABC-2FFE-11DE-9786-80000000A8C5</clTRID>
 </command>
</epp>
After consulting the developer of the EPP client for Python this is what it probably want how it should be formatted:
print(conn.contact_create(
    contact_id="some_EPP_ID_1234",
    voice="+1.7035555555",
    fax="+1.7035555556",
    email="[email protected]",
    contacts=[{
            "type": "int",
      "name": "John Doe",
            "org":"Example Inc.",
            "address": {
                "street":["123 Example Dr.", "Suite 100", ],
                "city": "Dulles",
                "sp": "VA",
                "pc": "20166-6503",
                "cc": "US",
            },
    }],
))
conn.close()
But obviously it fails... This is the error I get back from the EPP server:
EPP parser errors: unknown-55812a9e8740:0: Schemas validity error : Element \'{urn:ietf:params:xml:ns:contact-1.0}voice\': This element is not expected. Expected is ( {urn:ietf:params:xml:ns:contact-1.0}postalInfo ).
This is how the epp client constructs the create contact:
https://github.com/datahaven-net/epp-pyt...nt.py#L327
    def contact_create(self, contact_id, voice=None, fax=None, email=None, contacts=[], auth_info=None, **kwargs):
        return self.call(cmd=commands.contact.create % dict(
            cltrid=make_cltrid(),
            contact_id=contact_id,
            contact_fields='\n'.join([commands.contact.field1 % f for f in [
                {'field': 'voice', 'value': voice, },
                {'field': 'fax', 'value': fax, },
                {'field': 'email', 'value': email, },
            ] if f.get('value')]),
            postal_infos='\n'.join([
                commands.contact.postal_info1 % dict(
                    type=cont['type'],
                    postal_fields='\n'.join([
                        commands.contact.field2 % pf for pf in [
                            {'field': 'name', 'value': cont.get('name'), },
                            {'field': 'org', 'value': cont.get('org'), },
                        ] if pf.get('value')
                    ]),
                    address_fields='\n'.join([
                        commands.contact.field3 % dict(
                            field=afield,
                            value=', '.join(avalue) if isinstance(avalue, list) else avalue,
                        ) for (afield, avalue) in cont['address'].items() if avalue
                    ])
                ) for cont in contacts
            ]),
            auth_info='' if not auth_info else commands.contact.auth_info % auth_info,
        ), **kwargs)
In the RPC module of that client it is specified like this:
https://github.com/datahaven-net/epp-pyt...nt.py#L399
def cmd_contact_create(contact_id, email=None, voice=None, fax=None, auth_info=None, contacts_list=[], **args):
    """
    contacts_list item :
    {
        "name": "VeselinTest",
        "org":"whois",
        "address": {
            "street":["Street", "55"],
            "city": "City",
            "sp": "Nord Side",
            "cc": "AI",
            "pc": "1234AB"
        }
    }
    """
    cmd = {
        'cmd': 'contact_create',
        'args': {
            'id': contact_id,
            'contacts': [],
        },
    }
    if voice is not None:
        cmd['args']['voice'] = voice
    if fax is not None:
        cmd['args']['fax'] = fax
    if email is not None:
        cmd['args']['email'] = email
    if auth_info is not None:
        cmd['args']['auth_info'] = auth_info
    for cont in contacts_list[:]:
        international = copy.deepcopy(cont)
        international['type'] = 'int'
        if 'name' in international:
            international['name'] = '%s' % _tr(international['name'])
        if 'org' in international:
            international['org'] = '%s' % _tr(international['org'])
        if 'city' in international['address']:
            international['address']['city'] = '%s' % _tr(international['address']['city'])
        if 'sp' in international['address']:
            international['address']['sp'] = '%s' % _tr(international['address']['sp'])
        if 'pc' in international['address']:
            international['address']['pc'] = '%s' % _tr(international['address']['pc'])
        for i in range(len(international['address']['street'])):
            international['address']['street'][i] = '%s' % _tr(international['address']['street'][i])
        cmd['args']['contacts'].append(international)
    for cont in contacts_list[:]:
        loc = copy.deepcopy(cont)
        loc['type'] = 'loc'
        if 'name' in loc:
            loc['name'] = _enc(loc['name'])
        if 'org' in loc:
            loc['org'] = _enc(loc['org'])
        if 'city' in loc['address']:
            loc['address']['city'] = '%s' % _enc(loc['address']['city'])
        if 'sp' in loc['address']:
            loc['address']['sp'] = '%s' % _enc(loc['address']['sp'])
        if 'pc' in loc['address']:
            loc['address']['pc'] = '%s' % _enc(loc['address']['pc'])
        for i in range(len(loc['address']['street'])):
            loc['address']['street'][i] = '%s' % _enc(loc['address']['street'][i])
        cmd['args']['contacts'].append(loc)
    return run(cmd, **args)
Any insights? Ideas?

Thanks!