【问题标题】:XML Formatting IssueXML 格式问题
【发布时间】:2016-09-02 15:44:53
【问题描述】:

我是第一次使用 Salesforce SOAP API,所以我不熟悉 SOAP 格式问题等。我正在使用 lxml 库生成 XML,但似乎有格式问题。

我收到的错误是:“Envelope 元素的子元素必须是 Header 或 Body 元素”这很奇怪,因为当我查看由 SalesforceLeadConverter.build_xml() 方法生成的 XML 时,它看起来是正确的。这是

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <Header>
      <ns0:SessionHeader xmlns:ns0="urn">
          <ns0:sessionId>ldfkjskjdfksdfsdfsdf</ns0:sessionId>
      </ns0:SessionHeader>
   </Header>
   <Body>
      <ns1:convertLead xmlns:ns1="urn">
           <ns1:leadConverts>
               <ns1:leadId>00Qj000000PMV3h</ns1:leadId>
               <ns1:doNotCreateOpportunity>False</ns1:doNotCreateOpportunity>
               <ns1:sendNotificationEmail>False</ns1:sendNotificationEmail>
           </ns1:leadConverts>
       </ns1:convertLead>
   </Body>
</soapenv:Envelope>

这是生成 XML 的完整类和相关方法:

from lxml import etree

class SalesforceLeadConverter(object):

    def __init__(self, session_id, lead_id, **kwargs):
        """ Provides functionality for converting a Lead to a new or existing
        Account and create a new Contact or update an existing Contact.

        account_id: Optional; if specified, converts the Lead to a Contact
        associated with this Account.

        contact_id: Optional; if specified, converts the Lead into an existing
        Contact record, preventing the creation of a duplicate.
        """

        self.session_id = session_id
        self.lead_id = lead_id
        self.account_id = kwargs.get('account_id', False)
        self.contact_id = kwargs.get('contact_id', False)
        self.converted_status = kwargs.get('converted_status', False)
        self.do_not_create_opportunity = str(kwargs.get('do_not_create_opportunity', False))
        self.opportunity_name = kwargs.get('opportunity_name', False)
        self.owner_id = kwargs.get('owner_id', False)
        self.send_notification_email = str(kwargs.get('send_notification_email', False))

    def build_xml(self):
        S_NS = 'http://schemas.xmlsoap.org/soap/envelope/'
        S_PRE = '{' + S_NS + '}'
        root = etree.Element(S_PRE + 'Envelope', nsmap={'soapenv': S_NS})
        soapenv = etree.SubElement(root, 'Header')
        header = etree.SubElement(soapenv, '{urn}SessionHeader')
        sid = etree.SubElement(header, '{urn}sessionId').text=self.session_id
        soapenv2 = etree.SubElement(root, 'Body')
        urn2 = etree.SubElement(soapenv2, '{urn}convertLead')
        lead_converts = etree.SubElement(urn2, '{urn}leadConverts')
        lead_id = etree.SubElement(
            lead_converts,
            '{urn}leadId'
            ).text=self.lead_id
        do_not_create_opportunity = etree.SubElement(
            lead_converts,
            '{urn}doNotCreateOpportunity'
            ).text=self.do_not_create_opportunity
        send_notification_email = etree.SubElement(
            lead_converts,
            '{urn}sendNotificationEmail'
            ).text=self.send_notification_email
        xml_meta = """<?xml version="1.1" encoding="utf-8"?>"""

        return xml_meta + etree.tostring(root, encoding='utf-8')

【问题讨论】:

    标签: xml soap lxml


    【解决方案1】:

    SOAP Body 和 Header 需要一个命名空间。 此外,您的元素以 ns0 为前缀,ns1 也需要命名空间声明。

    所以您的有效 SOAP 将是:

    <?xml version="1.0" encoding="UTF-8"?>
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns0="your_namespace_here" xmlns:ns1="your_namespace_here">
       <soapenv:Header>
          <ns0:SessionHeader xmlns:ns0="urn">
              <ns0:sessionId>ldfkjskjdfksdfsdfsdf</ns0:sessionId>
          </ns0:SessionHeader>
       </soapenv:Header>
       <soapenv:Body>
          <ns1:convertLead xmlns:ns1="urn">
               <ns1:leadConverts>
                   <ns1:leadId>00Qj000000PMV3h</ns1:leadId>
                   <ns1:doNotCreateOpportunity>False</ns1:doNotCreateOpportunity>
                   <ns1:sendNotificationEmail>False</ns1:sendNotificationEmail>
               </ns1:leadConverts>
           </ns1:convertLead>
       </soapenv:Body>
    </soapenv:Envelope>
    

    【讨论】:

    • 谢谢,这让我走上了正确的道路!我发现我需要摆脱 ns0 和 ns1,最终这篇文章将我引导到所需的格式:stackoverflow.com/questions/19909473/…
    • 我想我已经解决了 XML 格式/命名空间问题,但现在我收到以下错误:“No operation available for request {urn:enterprise.soap.sforce.com}convertLead " -- 对我做错了什么有什么想法吗?
    【解决方案2】:

    下面修改后的 SalesforceLeadConverter 类解决了标题/正文命名空间问题(感谢 MGorgon 为我指明了正确的方向)。 This StackOverflow post 最终引导我找到正确的解决方案。

    请注意,虽然命名空间问题已解决,但下面的代码 仍然 不起作用...弹出另一个问题,我收到以下错误:

    “没有可用于请求 {enterprise.soap.sforce.com}convertLead 的操作”

    无论如何,这是我的 soap.py 文件:

    import requests
    from lxml.etree import Element, SubElement, tostring
    
    
    class SalesforceLeadConverter(object):
    
        def __init__(self, session_id, lead_id, **kwargs):
            """ Provides functionality for converting a Lead to a new or existing
            Account and create a new Contact or update an existing Contact.
    
            account_id: Optional; if specified, converts the Lead to a Contact
            associated with this Account.
    
            contact_id: Optional; if specified, converts the Lead into an existing
            Contact record, preventing the creation of a duplicate.
            """
    
            self.session_id = session_id
            self.lead_id = lead_id
            self.account_id = kwargs.get('account_id', False)
            self.contact_id = kwargs.get('contact_id', False)
            self.converted_status = kwargs.get('converted_status', False)
            self.do_not_create_opportunity = str(kwargs.get('do_not_create_opportunity', False))
            self.opportunity_name = kwargs.get('opportunity_name', False)
            self.owner_id = kwargs.get('owner_id', False)
            self.send_notification_email = str(kwargs.get('send_notification_email', False))
    
        def build_xml(self):
            schema_ns = 'http://schemas.xmlsoap.org/soap/envelope/'
            urn_ns = 'enterprise.soap.sforce.com'
            S_PRE = '{' + schema_ns + '}'
            envelope = Element(
                S_PRE + 'Envelope',
                nsmap={'soapenv': schema_ns, 'urn': urn_ns}
                )
            header = SubElement(envelope, '{%s}Header' % schema_ns)
            s_header = SubElement(header, '{%s}SessionHeader' % urn_ns)
            sid = SubElement(s_header, '{%s}sessionId' % urn_ns).text=self.session_id
            body = SubElement(envelope, '{%s}Body' % schema_ns)
            convert_lead = SubElement(body, '{%s}convertLead' % urn_ns)
            lead_converts = SubElement(convert_lead, '{%s}leadConverts' % urn_ns)
            lead_id = SubElement(
                lead_converts,
                '{%s}leadId' % urn_ns
                ).text=self.lead_id
            do_not_create_opportunity = SubElement(
                lead_converts,
                '{%s}doNotCreateOpportunity' % urn_ns
                ).text=self.do_not_create_opportunity
            send_notification_email = SubElement(
                lead_converts,
                '{%s}sendNotificationEmail' % urn_ns
                ).text=self.send_notification_email
    
            if self.account_id:
                account_id = SubElement(
                    lead_converts,
                    '{%s}accountId' % urn_ns
                    ).text=self.account_id
            if self.contact_id:
                contact_id = SubElement(
                    lead_converts,
                    '{%s}contactId' % urn_ns
                    ).text=self.contact_id
            if self.converted_status:
                converted_status = SubElement(
                    lead_converts,
                    '{%s}convertedStatus' % urn_ns
                    ).text=self.converted_status
            xml_meta = """<?xml version="1.1" encoding="utf-8"?>"""
    
            return xml_meta + tostring(envelope, encoding='utf-8')
    
        def post(self):
            xml = self.build_xml()
            headers = {'Content-Type':'text/xml', 'SOAPAction':'convertLead'}
            url = 'https://na1.salesforce.com/services/Soap/u/34.0'
            out = requests.post(url, data=xml, headers=headers)
            return out, out.text
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-07-18
      • 1970-01-01
      • 2013-11-02
      • 1970-01-01
      • 2020-06-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多