API orientées données data-oriented-apis

Les API orientées données permettent d’adresser le modèle de données dans son intégralité.

Vue d’ensemble du modèle de données overview-of-the-datamodel

Adobe Campaign ne propose pas une API de lecture dédiée par entité (pas de fonction de type getRecipient, getDelivery, etc.). Vous devez utiliser les méthodes de lecture et modification des données, QUERY & WRITER, pour accéder aux données du modèle.

Adobe Campaign permet de gérer les collections : un appel (query) permet de récupérer un ensemble d'informations collectées dans toute la base. Contrairement à un accès aux données en mode SQL, les API Adobe Campaign ne renvoient pas des colonnes de données mais une arborescence XML. Ainsi, Adobe Campaign crée des documents composites avec toutes les données collectées.

Ce mode de fonctionnement ne propose pas un mapping un pour un entre les attributs et éléments des documents XML et les colonnes des tables de la base de données.

Les documents XML sont stockés dans des champs de type MEMO de la base.

Description du modèle description-of-the-model

Vous devez impérativement connaître le modèle de données Adobe Campaign afin d'adresser correctement les champs de la base de données dans vos scripts.

Pour obtenir une présentation du modèle de données, consultez la section Description du modèle de données d’Adobe Campaign.

Query et Writer query-and-writer

Le schéma introductif suivant montre les échanges bas niveaux pour la lecture (ExecuteQuery) et l'écriture (Writer) entre la base de données et un client (pages web ou console cliente Adobe Campaign).

ExecuteQuery executequery

Pour les colonnes et les conditions, vous pouvez utiliser des Query.

Vous pouvez ainsi isoler le SQL sous-jacent. Le langage des requêtes est indépendant du moteur sous-jacent : certaines fonctions vont être re-mappées, ce qui peut générer de nombreux ordres SELECT SQL.

Voir à ce sujet la section Exemple sur la méthode 'ExecuteQuery' du schéma 'xtk:queryDef'.

La méthode ExecuteQuery est présentée dans ExecuteQuery (xtk:queryDef).

Write write

Les commandes Write permettent d'écrire des documents simples ou complexes, avec des écritures dans une ou plusieurs tables de la base.

Les API transactionnelles permettent de gérer les réconciliations via la commande updateOrInsert  : une même commande permet la création ou la mise à jour des données. Vous pouvez également paramétrer la fusion (merge) des modifications : ce mode de fonctionnement permet d'autoriser la mise à jour partielle.

La structure XML propose une vision logique des données et permet de s'affranchir de la structure physique de la table SQL.

La méthode Write est présentée dans Write / WriteCollection (xtk:session).

ExecuteQuery (xtk:queryDef) executequery--xtk-querydef-

Cette méthode permet d'effectuer des requêtes à partir de données associées à un schéma. Elle prend en paramètres une chaîne d'authentification (nécéssité d'être loggé) et un document XML décrivant la requête à soumettre. Le paramètre de retour est un document XML contenant le résultat de la requête au format du schéma sur lequel porte la requête.

Définition de la méthode "ExecuteQuery" dans le schéma "xtk:queryDef" :

<method name="ExecuteQuery" const="true">
  <parameters>
    <param desc="Output XML document" name="output" type="DOMDocument" inout="out"/>
  </parameters>
</method>
NOTE
Cette méthode est de type "const", les paramètres en entrée sont compris dans un document XML au format du schéma "xtk:queryDef".

Format du document XML de la requête en entrée format-of-the-xml-document-of-the-input-query

La structure du document XML de la requête est décrite dans le schéma "xtk:queryDef ", ce document décrit les différentes clauses d'une requête SQL : "select", "where", "order by", "group by", "having".

<queryDef schema="schema_key" operation="operation_type">
  <select>
    <node expr="expression1">
    <node expr="expression2">
    ...
  </select>
  <where>
    <condition expr="expression1"/>
    <condition expr="expression2"/>
    ...
  </where>
  <orderBy>
    <node expr="expression1">
    <node expr="expression2">
    ...
  </orderBy>
  <groupBy>
    <node expr="expression1">
    <node expr="expression2">
    ...
  </groupBy>
  <having>
    <condition expr="expression1"/>
    <condition expr="expression2"/>
    ...
  </having>
</queryDef>

Une sous-requête ( <subquery> ) peut être définie dans un élément <condition> . La syntaxe d’un élément <subquery> repose sur la syntaxe d’un <querydef>.

Exemple d’un <subquery> : </subquery>

<condition setOperator="NOT IN" expr="@id" enabledIf="$(/ignored/@ownerType)=1">
  <subQuery schema="xtk:operatorGroup">
     <select>
       <node expr="[@operator-id]" />
     </select>
     <where>
       <condition expr="[@group-id]=$long(../@owner-id)"/>
     </where>
   </subQuery>
</condition>

Une requête doit référencer un schéma de départ à partir de l'attribut schema.

Le type d'opération souhaité est renseigné dans l'attribut operation et contient une des valeurs suivantes :

  • get  : récupère un enregistrement de la table, et retourne une erreur si la donnée n'existe pas,
  • getIfExists  : récupère un enregistrement de la table, et retourne un document vide si la donnée n'existe pas,
  • select  : crée un curseur pour retourner plusieurs enregistrements, et retourne un document vide si aucune données,
  • count  : retourne un comptage des données.

La syntaxe XPath sert à localiser les données en fonction du schéma de départ. Pour plus d’informations sur XPath, voir Schémas de données.

Exemple avec l'opération 'get' example-with-the--get--operation

Récupère le nom et le prénom d’un destinataire (schéma « nms:recipient ») avec un filtre sur l’e-mail.

<queryDef schema="nms:recipient" operation="get">
  <!-- fields to retrieve -->
  <select>
    <node expr="@firstName"/>
    <node expr="@lastName"/>
  </select>

  <!-- condition on email -->
  <where>
    <condition expr="@email= 'john.doe@aol.com'"/>
  </where>
</queryDef>

Exemple avec l’opération « select » example-with-the--select--operation

Retourne la liste des destinataires filtrés sur un dossier et le domaine de l’e-mail avec un tri décroissant sur la date de naissance.

<queryDef schema="nms:recipient" operation="select">
  <select>
    <node expr="@email"/>
    <!-- builds a string with the concatenation of the last name and first name separated by a dash -->
    <node expr="@lastName+'-'+@firstName"/>
    <!-- get year of birth date -->
    <node expr="Year(@birthDate)"/>
  </select>

  <where>
     <condition expr="[@folder-id] = 1234 and @domain like 'Adobe%'"/>
  </where>

  <!-- order by birth date -->
  <orderBy>
    <node expr="@birthDate" sortDesc="true"/> <!-- by default sortDesc="false" -->
  </orderBy>
</queryDef>

Les expressions peuvent être des champs simples ou des expressions complexes telles que les opérations arithmétiques ou la concaténation de chaînes.

Pour limiter le nombre d’enregistrements à retourner, il faut ajouter l’attribut lineCount à l’élément <querydef>.

Pour limiter à 100 le nombre d'enregistrements retournés par la requête :

<queryDef schema="nms:recipient" operation="select" lineCount="100">
...

Pour récupérer les 100 enregistrements suivants, lancer de nouveau la même requête en ajoutant l'attribut startLine.

<queryDef schema="nms:recipient" operation="select" lineCount="100" startLine="100">
...

Exemple avec l'opération 'count' example-with-the--count--operation

Pour compter le nombre d'enregistrements sur une requête :

<queryDef schema="nms:recipient" operation="count"">
  <!-- condition on the folder and domain of the email -->
  <where>
    <condition expr="[@folder-id] = 1234" and @domain like 'Adobe%'"/>
  </where>
</queryDef>
NOTE
Encore une fois, nous utilisons la condition de l’exemple précédent. Les <select> et clauses ne sont pas utilisés. </select>

Groupement de données data-grouping

Pour récupérer les adresses e-mail référencées plus d’une fois :

<queryDef schema="nms:recipient" operation="select">
  <select>
    <node expr="@email"/>
    <node expr="count(@email)"/>
  </select>

  <!-- email grouping clause -->
  <groupby>
    <node expr="@email"/>
  </groupby>

  <!-- grouping condition -->
  <having>
    <condition expr="count(@email) > 1"/>
  </having>

</queryDef>

On peut simplifier la requête en renseignant l'attribut groupBy directement sur le champ à grouper :

<select>
  <node expr="@email" groupBy="true"/>
</select>
NOTE
Il n’est plus nécessaire de renseigner l’élément <groupby>.

Parenthésage dans les conditions bracketing-in-conditions

Voici deux exemples de parenthésages sur une même condition.

  • La version simple en une seule expression :

    code language-xml
    <where>
      <condition expr="(@age > 15 or @age <= 45) and  (@city = 'Newton' or @city = 'Culver City') "/>
    </where>
    
  • La version structurée avec des éléments <condition> :

    code language-xml
    <where>
      <condition bool-operator="AND">
        <condition expr="@age > 15" bool-operator="OR"/>
        <condition expr="@age <= 45"/>
      </condition>
      <condition>
        <condition expr="@city = 'Newton'" bool-operator="OR"/>
        <condition expr="@city = 'Culver City'"/>
      </condition>
    </where>
    

Il est possible de remplacer l'opérateur 'OR' avec l'opérateur 'IN' lorsque plusieurs conditions portent sur le même champ :

<where>
  <condition>
    <condition expr="@age IN (15, 45)"/>
    <condition expr="@city IN ('Newton', 'Culver City')"/>
  </condition>
</where>

Cette syntaxe simplifie la requête lorsque plus de deux données sont utilisées dans la condition.

  • Liens 1-1 ou N-1 : lorsque la table possède la clé étrangère (le lien part de la table), on peut filtrer ou récupérer directement les champs de la table liée.

    Exemple de filtre sur le libellé du dossier :

    code language-xml
    <where>
      <condition expr="[folder/@label] like 'Segment%'"/>
    </where>
    

    Pour récupérer les champs du dossier à partir du schéma "nms:recipient" :

    code language-xml
    <select>
      <!-- label of recipient folder -->
      <node expr="[folder/@label]"/>
      <!-- displays the string count of the folder -->
      <node expr="partition"/>
    </select>
    
  • Liens de collections (1-N) : le filtrage sur les champs d'une table de collection doit passer par l'opérateur EXISTS ou NOT EXISTS.

    Pour filtrer les destinataires abonnés au service d'information 'Newsletter' :

    code language-xml
    <where>
      <condition expr="subscription" setOperator="EXISTS">
        <condition expr="@name = 'Newsletter'"/>
      </condition>
    </where>
    

    La récupération directe des champs d’un lien de collection à partir de la clause <select> n’est pas recommandée, car la requête renvoie un produit cardinal. Elle est utilisée uniquement lorsque la table liée contient un seul enregistrement (exemple <node expr="">).

    Exemple sur le lien de collection "subscription" :

    code language-xml
    <select>
      <node expr="subscription/@label"/>
    </select>
    

    Il est possible de récupérer une sous-liste contenant les éléments d’un lien de collection dans la clause <select>. Les XPath des champs référencés sont contextuels à partir de l’élément de collection.

    Les éléments de filtrage ( <orderby> ) et de restriction ( <where> ) peuvent être ajoutés à l’élément de collection.

    Dans cet exemple, la requête retourne l’e-mail de chaque destinataire ainsi que la liste des services d’information auxquels il est abonné :

    code language-xml
    <queryDef schema="nms:recipient" operation="select">
      <select>
        <node expr="@email"/>
    
        <!-- collection table (unbound type) -->
        <node expr="subscription">
          <node expr="[service/@label]"/>
          <!-- sub-condition on the collection table -->
          <where>
            <condition expr="@expirationDate >= GetDate()"/>
          </where>
          <orderBy>
            <node expr="@expirationDate"/>
          </orderBy>
        </node>
      </select>
    </queryDef>
    

Binding des paramètres de la clause 'where' et 'select' binding-the-parameters-of-the--where--and--select--clause

Le binding des paramètres laisse le moteur fixer les valeurs des paramètres utilisés dans la requête. Ceci est très utile car l'échappement des valeurs est à la charge du moteur et on bénéficie en plus d'un cache sur les paramètres à récupérer.

Lorsqu’une requête est créée, les valeurs « liées » sont remplacées par un caractère (? dans ODBC, #[index]# dans postgres…) dans le corps de la requête SQL.

<select>
  <!--the value will be bound by the engine -->
  <node expr="@startDate = #2002/02/01#"/>
  <!-- the value will not be bound by the engine but visible directly in the query -->
  <node expr="@startDate = #2002/02/01#" noSqlBind="true"/>
</select>

Pour ne pas binder un paramètre, il faut renseigner l'attribut "noSqlBind" avec la valeur "true".

IMPORTANT
Dans le cas où la requête comprend des instructions du type "order-by" ou "group-by", les moteurs de base de données ne peuvent pas "binder" les valeurs. Il est donc indispensable de placer dans la même requête l'attribut @noSqlBind="true" sur les instructions "select" et/ou "where".

Format du document de sortie output-document-format

Le paramètre de retour est un document XML au format du schéma associé à la requête.

Exemple de retour à partir du schéma "nms:recipient" sur une opération de type "get" :

<recipient email="john.doe@adobe.com" lastName"Doe" firstName="John"/>

Sur une opération de type "select", le document retourné est une énumération d'éléments :

<!-- the name of the first element does not matter -->
<recipient-collection>
  <recipient email="john.doe@adobe.com" lastName"Doe" firstName="John"/>
  <recipient email="peter.martinez@adobe.com" lastName"Martinez" firstName="Peter"/>
  <recipient...
</recipient-collection>

Exemple de document de retour sur une opération de type "count" :

<recipient count="3"/>

Alias alias

Un alias permet de modifier l’emplacement des données dans le document en sortie. L’attribut alias doit être renseigné avec un XPath sur le champ correspondant.

<queryDef schema="nms:recipient" operation="get">
  <select>
    <node expr="@firstName" alias="@firstName"/>
    <node expr="@lastName"/>
    <node expr="[folder/@label]" alias="@My_folder"/>
  </select>
</queryDef>

Retourne :

<recipient My_folder="Recipients" First name ="John" lastName="Doe"/>

A la place de :

<recipient firstName="John" lastName="Doe">
  <folder label="Recipients"/>
</recipient>

Exemple de messages SOAP example-of-soap-messages

  • Requête:

    code language-xml
    <?xml version='1.0' encoding='ISO-8859-1'?>
    <SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='http://xml.apache.org/xml-soap' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
      <SOAP-ENV:Body>
        <ExecuteQuery xmlns='urn:xtk:queryDef' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
          <__sessiontoken xsi:type='xsd:string'/>
          <entity xsi:type='ns:Element' SOAP-ENV:encodingStyle='http://xml.apache.org/xml-soap/literalxml'>
            <queryDef operation="get" schema="nms:recipient" xtkschema="xtk:queryDef">
              <select>
                <node expr="@email"/>
                <node expr="@lastName"/>
                <node expr="@firstName"/>
              </select>
              <where>
                <condition expr="@id = 3599"/>
              </where>
            </queryDef>
          </entity>
        </ExecuteQuery>
      </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>
    
  • Réponse :

    code language-xml
    <?xml version='1.0' encoding='ISO-8859-1'?>
    <SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='http://xml.apache.org/xml-soap' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
      <SOAP-ENV:Body>
        <ExecuteQueryResponse xmlns='urn:xtk:queryDef' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
          <pdomOutput xsi:type='ns:Element' SOAP-ENV:encodingStyle='http://xml.apache.org/xml-soap/literalxml'>
            <recipient email="john.doe@adobe.com" lastName"Doe" firstName="John"/>
          </pdomOutput>
        </ExecuteQueryResponse>
      </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>
    

Write / WriteCollection (xtk:session) write---writecollection--xtk-session-

Ces services permettent l'insertion/la mise à jour/la suppression d'une entité (méthode "Write") ou d'une collection d'entités (méthode "WriteCollection").

Les entités à mettre à jour sont associées à un schéma de données. Les paramètres en entrée sont une chaîne d'authentification (nécéssité d'être loggé) et un document XML contenant les données à mettre à jour.

Ce document est complété par des instructions permettant de paramétrer les procédures d'écriture.

L'appel ne retourne pas de données, hormis les erreurs.

Définition des méthodes "Write" et "WriteCollection" dans le schéma "xtk:session" :

<method name="Write" static="true">
  <parameters>
    <param name="doc" type="DOMDocument" desc="Difference document"/>
  </parameters>
</method>
<method name="WriteCollection" static="true">
  <parameters>
    <param name="doc" type="DOMDocument" desc="Difference collection document"/>
  </parameters>
</method>
NOTE
Cette méthode est de type "static", les paramètres en entrée sont compris dans un document XML au format du schéma à mettre à jour.

Vue d’ensemble overview

La réconciliation des données s'opère à partir de la définition des clés renseignées dans le schéma associé. La procédure d'écriture va rechercher la première clé éligible en fonction des données renseignées dans le document en entrée. L'entité est insérée ou mise à jour en fonction de son existence dans la base de données.

La clé du schéma de l'entité à mettre à jour est renseignée à partir de l'attribut xtkschema.

La clé de réconciliation peut être forcée avec l’attribut _key contenant la liste des XPath qui composent la clé (séparés par une virgule).

Il est possible de forcer le type d'opération en renseignant l'attribut _operation avec les valeurs suivantes :

  • insert  : force l'insertion de l'enregistrement (la clé de réconciliation n'est pas utilisée),
  • insertOrUpdate  : met à jour ou insère l'enregistrement en fonction de la clé de réconciliation (mode par défaut),
  • update  : met à jour l'enregistrement, ne fait rien si la donnée n'existe pas,
  • delete  : supprime les enregistrements,
  • none  : utilisé uniquement pour la réconciliation de lien, sans mise à jour ni insertion.

Exemple avec la méthode 'Write' example-with-the--write--method

Mise à jour ou insertion d’un destinataire (opération « insertOrUpdate » implicite) avec son adresse e-mail, sa date de naissance et sa ville :

<recipient xtkschema="nms:recipient" email="john.doe@adobe.com" birthDate="1956/05/04" folder-id=1203 _key="@email, [@folder-id]">
  <location city="Newton"/>
</recipient>

Suppression d'un destinataire :

<recipient xtkschema="nms:recipient" _operation="delete" email="rene.dupont@adobe.com" folder-id=1203 _key="@email, [@folder-id]"/>
NOTE
Dans le cas d'une opération en suppression, le document en entrée ne doit contenir que les champs qui composent la clé de réconciliation.

Exemple avec la méthode 'WriteCollection' example-with-the--writecollection--method

Mise à jour ou insertion sur plusieurs destinataires :

<recipient-collection xtkschema="nms:recipient">
  <recipient email="john.doe@adobe.com" firstName="John" lastName="Doe" _key="@email"/>
  <recipient email="peter.martinez@adobe.com" firstName="Peter" lastName="Martinez" _key="@email"/>
  <recipient ...
</recipient-collection>

Exemple 1 example-1

Associer le dossier sur un destinataire à partir de son nom interne (@name).

<recipient _key="[folder/@name], @email" email="john.doe@adobe.net" lastName="Doe" firstName="John" xtkschema="nms:recipient">
  <folder name="Folder2" _operation="none"/>
</recipient>

Les attributs "_key" et "_operation" peuvent être renseignés sur un élément lié, le comportement sur cet élément est le même que sur l'élément principal du schéma de départ.

La définition de la clé de l’entité principale (« nms:recipient ») est composée d’un champ provenant d’une table liée (élément <folder> du schéma « xtk:folder ») et de l’e-mail.

NOTE
L’opération « aucun » renseignée sur l’élément dossier définit une réconciliation sur le dossier sans mise à jour ni insertion.

Exemple 2 example-2

Mettre à jour la société (table liée de schéma "cus:company") à partir d'un destinataire :

<recipient _key="[folder/@name], @email" email="john.doe@adobe.net" lastName="Doe" firstName="John" xtkschema="nms:recipient">
  <company name="adobe" code="ERT12T" _key="@name" _operation="update"/>
</recipient>

Exemple 3 example-3

Ajouter un destinataire dans un groupe avec la table de relation des groupes ("nms:rcpGrpRel") :

<recipient _key="@email" email="martin.ledger@adobe.net" xtkschema="nms:recipient">
  <rcpGrpRel _key="[rcpGroup/@name]">
    <rcpGroup name="GRP1"/>
  </rcpGrpRel>
</recipient>
NOTE
La définition de la clé n’est pas renseignée sur l’élément <rcpgroup> car une clé implicite sur le nom du groupe est définie dans la schéma "nms:group".

Eléments de collections XML xml-collection-elements

Par défaut, pour mettre à jour les éléments de collection XML, il faut renseigner tous les éléments de collection. Les données de la base seront remplacées par les données du document en entrée. Si le document contient uniquement les éléments à mettre à jour, vous devez renseigner l'attribut "_operation" sur tous les éléments de collection à mettre à jour afin de forcer la fusion (merge) avec les données XML de la base.

Exemple de messages SOAP example-of-soap-messages-1

  • Requête:

    code language-xml
    <?xml version='1.0' encoding='ISO-8859-1'?>
    <SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='http://xml.apache.org/xml-soap' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
      <SOAP-ENV:Body>
        <Write xmlns='urn:xtk:persist' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
          <__sessiontoken xsi:type='xsd:string'/>
          <domDoc xsi:type='ns:Element' SOAP-ENV:encodingStyle='http://xml.apache.org/xml-soap/literalxml'>
            <recipient xtkschema="nms:recipient" email="rene.dupont@adobe.com" firstName="René" lastName="Dupont" _key="@email">
          </domDoc>
        </Write>
      </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>
    
  • Réponse :

    code language-xml
    <?xml version='1.0' encoding='ISO-8859-1'?>
    <SOAP-ENV:Envelope xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:ns='http://xml.apache.org/xml-soap' xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
      <SOAP-ENV:Body>
        <WriteResponse xmlns='urn:' SOAP-ENV:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'>
        </WriteResponse>
      </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>
    

    Retour avec erreur :

    code language-xml
    <?xml version='1.0'?>
    <SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'>
      <SOAP-ENV:Body>
        <SOAP-ENV:Fault>
          <faultcode>SOAP-ENV:Server</faultcode>
          <faultstring xsi:type="xsd:string">Error while executing the method 'Write' of service 'xtk:persist'.</faultstring>
          <detail xsi:type="xsd:string">PostgreSQL error: ERROR:  duplicate key violates unique constraint &quot;nmsrecipient_id&quot;Impossible to save document of type 'Recipients (nms:recipient)'</detail>
        </SOAP-ENV:Fault>
      </SOAP-ENV:Body>
    </SOAP-ENV:Envelope>
    
recommendation-more-help
601d79c3-e613-4db3-889a-ae959cd9e3e1