@adobe/acc-js-sdk 1.1.10 → 1.1.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2170
- package/docs/404.html +11 -0
- package/docs/Gemfile +35 -0
- package/docs/Gemfile.lock +270 -0
- package/docs/_config.yml +55 -0
- package/docs/_data/navigation.yml +119 -0
- package/docs/_includes/navigation.html +33 -0
- package/docs/_layouts/default.html +21 -0
- package/docs/_layouts/home.html +4 -0
- package/docs/_layouts/page.html +5 -0
- package/docs/_layouts/post.html +7 -0
- package/docs/_posts/2022-10-14-welcome.html +149 -0
- package/docs/application.html +367 -0
- package/docs/architecture.html +24 -0
- package/docs/assets/css/styles.css +362 -0
- package/docs/assets/images/adobe-campaign-256.png +0 -0
- package/docs/assets/images/architecture.png +0 -0
- package/docs/assets/images/ref.svg +6 -0
- package/docs/badgerFish.html +14 -0
- package/docs/bestPractices.html +189 -0
- package/docs/blog.html +18 -0
- package/docs/buildAndRun.html +96 -0
- package/docs/caches.html +68 -0
- package/docs/changeLog.html +263 -0
- package/docs/checkList.html +168 -0
- package/docs/concepts.html +130 -0
- package/docs/connecting.html +210 -0
- package/docs/connectionParameters.html +109 -0
- package/docs/contribute.html +54 -0
- package/docs/dataTypes.html +124 -0
- package/docs/differences.html +4 -0
- package/docs/documentation.html +21 -0
- package/docs/domHelper.html +88 -0
- package/docs/dynamicInvoke.html +36 -0
- package/docs/entityAccessor.html +22 -0
- package/docs/errors.html +47 -0
- package/docs/escaping.html +76 -0
- package/docs/favicon.png +0 -0
- package/docs/healthCheck.html +66 -0
- package/docs/httpHeaders.html +78 -0
- package/docs/index.html +64 -0
- package/docs/installation.html +34 -0
- package/docs/license.html +208 -0
- package/docs/messageCenter.html +80 -0
- package/docs/methodLevelRepresentation.html +12 -0
- package/docs/midSourcing.html +19 -0
- package/docs/observability.html +169 -0
- package/docs/passwords.html +27 -0
- package/docs/profiles.html +103 -0
- package/docs/pushDown.html +13 -0
- package/docs/quickstart.html +69 -0
- package/docs/release.html +52 -0
- package/docs/samples.html +82 -0
- package/docs/simpleJson.html +88 -0
- package/docs/soapAPIs.html +234 -0
- package/docs/timeouts.html +23 -0
- package/docs/transport.html +45 -0
- package/docs/troubleshooting.html +17 -0
- package/docs/writeDoc.html +208 -0
- package/docs/xml2json.html +96 -0
- package/docs/xtkCaster.html +67 -0
- package/docs/xtkInterface.html +20 -0
- package/docs/xtkOption.html +54 -0
- package/docs/xtkPackage.html +16 -0
- package/docs/xtkPersist.html +213 -0
- package/docs/xtkQueryDef.html +245 -0
- package/docs/xtkSchema.html +39 -0
- package/docs/xtkSession.html +29 -0
- package/docs/xtkWorkflow.html +28 -0
- package/docs/xtkWrite.html +51 -0
- package/package-lock.json +1 -1
- package/package.json +1 -1
- package/src/application.js +15 -5
- package/src/campaign.js +1 -1
- package/src/soap.js +6 -6
- package/test/application.test.js +21 -6
- package/test/soap.test.js +13 -0
- package/CHANGELOG.md +0 -252
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: page
|
|
3
|
+
title: SOAP APIs
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<p>The NLWS object allows to dynamically perform SOAP calls on the targetted Campaign instance.
|
|
7
|
+
</p>
|
|
8
|
+
<pre class="code">
|
|
9
|
+
const NLWS = client.NLWS;
|
|
10
|
+
</pre>
|
|
11
|
+
|
|
12
|
+
<p>
|
|
13
|
+
Technically, NLWS is a JavaScript proxy whose properties are dynamically constructed. It has properties
|
|
14
|
+
for each schema, for instance <b>NLWS.xtkSession</b> corresponds to the APIs of the <b>xtk:session</b> schema.
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
<p>
|
|
18
|
+
Methods can then be called as <b>asynchronous</b> JavaScript functions. Note that in Campaign, method names
|
|
19
|
+
usually start with a capital letter (ex: xtk:session#GetServerTime where "G" is a capital letter).
|
|
20
|
+
JavaScript convention is to use a lower case first character for function names, and the SDK will follow
|
|
21
|
+
JS conventions.
|
|
22
|
+
</p>
|
|
23
|
+
|
|
24
|
+
<pre class="code">
|
|
25
|
+
const result = await NLWS.xtkSession.getServerTime();
|
|
26
|
+
</pre>
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
<h1>Passing parameters</h1>
|
|
36
|
+
|
|
37
|
+
<p>
|
|
38
|
+
In order to know which parameters to pass to a method and which parameters are returned, look at the method definition in the schema.
|
|
39
|
+
You can also capture SOAP requests and responses from a real session. The method definition in the schema will have a list of
|
|
40
|
+
parameters. Parameters can be qualified as <b>in</b>, <b>out</b>, or <b>inout</b>. Unqualified parameters are considered to be <b>in</b>
|
|
41
|
+
(input) parameters.
|
|
42
|
+
</p>
|
|
43
|
+
|
|
44
|
+
<p>
|
|
45
|
+
The parameters marked as <b>in</b>, <b>inout</b> or without an inout attribubte are input parameters of the API and must be passed
|
|
46
|
+
in JavaScript to the method call. Refer to the <a href="{{ site.baseurl }}/dataTypes.hml">Data Types</a> page for a comprehensive view of all the data
|
|
47
|
+
types supported by the SDK. Parameters are passed positionally and not by name, i.e. you must pass each input parameter in the right
|
|
48
|
+
order, skipping output parameters.
|
|
49
|
+
</p>
|
|
50
|
+
|
|
51
|
+
<pre class="code">
|
|
52
|
+
<method name="GetFilesToDownload" static="true">
|
|
53
|
+
<parameters>
|
|
54
|
+
<param name="deliveryId" type="long" inout="in"/>
|
|
55
|
+
<param name="filesToDownload" type="DOMDocument" inout="out"/>
|
|
56
|
+
<param name="filesNotToDownload" type="DOMDocument" inout="out"/>
|
|
57
|
+
</parameters>
|
|
58
|
+
</method>
|
|
59
|
+
</pre>
|
|
60
|
+
<p class="caption">An example of a method definition with in and out parameters</p>
|
|
61
|
+
|
|
62
|
+
<p>
|
|
63
|
+
Another important attribute is the <b>static</b> attribute of each method. Static methods can be called directly. Non-static methods
|
|
64
|
+
need an object instance. In the example above, the method takes one input parameter, a numeric delivery id, and returns 2 DOM
|
|
65
|
+
documents containing a list of files to downoad and a list of files not to download.
|
|
66
|
+
</p>
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
<pre class="code">
|
|
70
|
+
const deliveryId = 1234;
|
|
71
|
+
const [filesToDownload, filesNotToDownload] = client.NLWS.nmsDelivery.getFilesToDownload(deliveryId);
|
|
72
|
+
</pre>
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
<h1>XML & JSON</h1>
|
|
76
|
+
<p>
|
|
77
|
+
In Campaign, many method attributes are XML elements or documents, as well as many return types. It's not very easy to use in JavaScript, so the SDK supports automatic XML<=> JSON conversion. Of yourse, you can still use XML if you want.
|
|
78
|
+
</p>
|
|
79
|
+
|
|
80
|
+
<p>We're supporting several flavors of JSON in addition to XML.</p>
|
|
81
|
+
<ul>
|
|
82
|
+
<li><b>SimpleJson</b> which is the recommeded and default representation</li>
|
|
83
|
+
<li><b>BadgerFish</b> which was the only and default before 1.0.0, and is now a legacy flavor of JSON. It's a little bit complex and was deprecated in favor of `SimpleJson` (http://www.sklar.com/badgerfish/) </li>
|
|
84
|
+
<li><b>xml</b> which can be use to perform no transformation: Campaign XML is returned directly without any transformations.</li>
|
|
85
|
+
</ul>
|
|
86
|
+
|
|
87
|
+
<p>The representation can set when creating a client. It's recommended to keep it to <b>SimpleJson</b>.</p>
|
|
88
|
+
<pre class="code">
|
|
89
|
+
const client = await sdk.init("https://myInstance.campaign.adobe.com", "admin", "admin", { representation: "SimpleJson" });
|
|
90
|
+
</pre>
|
|
91
|
+
|
|
92
|
+
<p>Here's an example of a queryDef in SimpleJson. This query will return an array containing one item for each external account in the Campaign database. Each item will contain the account id and name.</p>
|
|
93
|
+
|
|
94
|
+
<pre class="code">
|
|
95
|
+
const queryDef = {
|
|
96
|
+
schema: "nms:extAccount",
|
|
97
|
+
operation: "select",
|
|
98
|
+
select: {
|
|
99
|
+
node: [
|
|
100
|
+
{ expr: "@id" },
|
|
101
|
+
{ expr: "@name" }
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
</pre>
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
<h1>Calling static methods</h1>
|
|
111
|
+
<p>
|
|
112
|
+
Static SOAP methods are the easiest to call. Once you have a <b>NLWS</b> object and have logged on to the server, call a static mathod as followed. This example will use the <b>xtk:session#GetServerTime</b> method to displayt the current timestamp on the server.
|
|
113
|
+
</p>
|
|
114
|
+
|
|
115
|
+
<pre class="code">
|
|
116
|
+
const NLWS = client.NLWS;
|
|
117
|
+
result = await NLWS.xtkSession.getServerTime();
|
|
118
|
+
console.log(result);
|
|
119
|
+
</pre>
|
|
120
|
+
|
|
121
|
+
<p></p>
|
|
122
|
+
<ul>
|
|
123
|
+
<li><b>xtkSession</b> is made of the namespace and entity to which the API applies. For instance <b>xtk:session</b> -> <b>xtkSession</b></li>
|
|
124
|
+
<li><b>getServerTime</b> is the method name. In ACC, method names start with an upper case letter, but in JS SDK you can put it in lower case too (which is preferred for JavaScript code).</li>
|
|
125
|
+
</ul>
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
<h1>Returning multiple values</h1>
|
|
131
|
+
<p>Campaign APIs can return one or multiple values. The SDK uses the following convention:</p>
|
|
132
|
+
<ul>
|
|
133
|
+
<li>no return value -> returns "null"</li>
|
|
134
|
+
<li>one return value -> returns the value directly</li>
|
|
135
|
+
<li>more that one return value -> returns an array of values</li>
|
|
136
|
+
</ul>
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
<h1>Calling non-static APIs</h1>
|
|
141
|
+
|
|
142
|
+
<p>To call a non-static API, you need an object to call the API on. You create an object with the <b>create</b> method.
|
|
143
|
+
For instance, here's how one creates a QueryDef object.</p>
|
|
144
|
+
|
|
145
|
+
<pre class="code">
|
|
146
|
+
const queryDef = {
|
|
147
|
+
schema: "nms:extAccount",
|
|
148
|
+
operation: "select",
|
|
149
|
+
select: {
|
|
150
|
+
node: [
|
|
151
|
+
{ expr: "@id" },
|
|
152
|
+
{ expr: "@name" }
|
|
153
|
+
]
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
const query = NLWS.xtkQueryDef.create(queryDef);
|
|
157
|
+
</pre>
|
|
158
|
+
|
|
159
|
+
<p>Note: the returned object is opaque and private, it should not be directly manipulated.</p>
|
|
160
|
+
|
|
161
|
+
<p>The method can then be called directly on the object</p>
|
|
162
|
+
<pre class="code">
|
|
163
|
+
const extAccounts = await query.executeQuery();
|
|
164
|
+
</pre>
|
|
165
|
+
|
|
166
|
+
<p>In this example, the result is as follows</p>
|
|
167
|
+
|
|
168
|
+
<pre class="code">
|
|
169
|
+
{ extAccount:[
|
|
170
|
+
{ id: "2523379", name: "cda_snowflake_extaccount" },
|
|
171
|
+
{ id: "1782", name: "defaultPopAccount" },
|
|
172
|
+
{ id: "3643548", name: "v8" }
|
|
173
|
+
]}
|
|
174
|
+
</pre>
|
|
175
|
+
|
|
176
|
+
<p>Some methods can mutate the object on which they apply. This is for instance the case of the xtk:queryDef#SelectAll method. You call it on a queryDef, and it internally returns a new query definition which contain select nodes for all the nodes of the schema. When such a method is called, the SDK will know how to "mutate" the corresponding object.</p>
|
|
177
|
+
|
|
178
|
+
<pre class="code">
|
|
179
|
+
const queryDef = {
|
|
180
|
+
schema: "xtk:option",
|
|
181
|
+
operation: "get",
|
|
182
|
+
where: { condition: [ { expr:`@name='XtkDatabaseId'` } ] }
|
|
183
|
+
};
|
|
184
|
+
const query = client.NLWS.xtkQueryDef.create(queryDef);
|
|
185
|
+
await query.selectAll(false);
|
|
186
|
+
var result = await query.executeQuery();
|
|
187
|
+
</pre>
|
|
188
|
+
|
|
189
|
+
<p>In the previous example, a queryDef is created without any select nodes. Then the selectAll method is called. After the call, the JavaScript queryDef object will contain a select elements with all the nodes corresponding to attributes of the xtk:option schema.</p>
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
<h1>Passing XML parameters</h1>
|
|
194
|
+
<p>Many Campaign APIs take arguments which are DOM documents or DOM elements. For example, the nms:delivery#DeployTriggerMessages first argument is a DOMElement which is supposed to be a <b><where></b> clause used as a condition to select Message Center deliveries to publish.</p>
|
|
195
|
+
|
|
196
|
+
<pre class="code">
|
|
197
|
+
<method name="DeployTriggerMessages" static="true">
|
|
198
|
+
<parameters>
|
|
199
|
+
<param inout="in" name="deliveries" type="DOMElement"/>
|
|
200
|
+
<param inout="in" name="localPublish" type="boolean"/>
|
|
201
|
+
</parameters>
|
|
202
|
+
</method>
|
|
203
|
+
</pre>
|
|
204
|
+
|
|
205
|
+
<p>For example, one would want to use the following condition to republish a particular delivery</p>
|
|
206
|
+
|
|
207
|
+
<pre class="code">
|
|
208
|
+
await client.NLWS.nmsDelivery.DeployTriggerMessages({
|
|
209
|
+
condition: [ {
|
|
210
|
+
expr: "@internalName='DM23'"
|
|
211
|
+
}]
|
|
212
|
+
}, false);
|
|
213
|
+
</pre>
|
|
214
|
+
|
|
215
|
+
<p>The JSON object corresponds to the following XML</p>
|
|
216
|
+
<pre class="code">
|
|
217
|
+
<where>
|
|
218
|
+
<condition expr="@internalName='DM23'"/>
|
|
219
|
+
</where>
|
|
220
|
+
</pre>
|
|
221
|
+
|
|
222
|
+
<p>Note that in XML, unlike JSON, the root element <b><where></b> is explicitely named "where". When converting JSON to XML, there is no way for the SDK to know which tag name to used for the root XML element. The SDK contains some code to set it for the most common situation, but will rely on the user to specify, when necessary, the name of the root elment. This can be done using the <b>xtkschema</b> (all case insensitive) attribute as follows:</p>
|
|
223
|
+
<pre class="code">
|
|
224
|
+
await client.NLWS.nmsDelivery.DeployTriggerMessages({
|
|
225
|
+
xtkschema: 'xtk:where',
|
|
226
|
+
condition: [ {
|
|
227
|
+
expr: "@internalName='DM23'"
|
|
228
|
+
}]
|
|
229
|
+
}, false);
|
|
230
|
+
</pre>
|
|
231
|
+
|
|
232
|
+
<p>When the <b>xtkschema</b> attribute is set, the part after the colon (i.e. "where" in this example) will be used as the root element, effectively generating the right XML.</p>
|
|
233
|
+
|
|
234
|
+
<p>In our example, the `DeployTriggerMessages` will work properly regardless of the XML root of its `deliveries` parameter, so it's not needed to actually set the `xtkschema` attribute, but it's a best practice to do so, because some APIs will actually depend on receiving the right tag name.</p>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: page
|
|
3
|
+
title: Handling timeouts
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<p>By default, the SDK has a timeout of 5s when running in a node.js environment, and uses the browser defaults when run inside a browser (using the fetch API).</p>
|
|
7
|
+
|
|
8
|
+
<p>It is possible to overwrite the transport layer (see <b>The Transport Protocol</b> and use your own code to make and configure HTTP requests) to tune the timeout value. It is a bit cumbersome though.</p>
|
|
9
|
+
|
|
10
|
+
<p>Instead, you can use the <b>timeout</b> parameter, and set it either globally, as a connection parameter, or even at the API call level but using the <b>PushDown</b> mechanism described below.</p>
|
|
11
|
+
|
|
12
|
+
<p>Sets a timeout of 10s gloally</p>
|
|
13
|
+
<pre class="code">
|
|
14
|
+
const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword(
|
|
15
|
+
"https://myInstance.campaign.adobe.com",
|
|
16
|
+
"admin", "admin",
|
|
17
|
+
{ timeout: 10000 });
|
|
18
|
+
</pre>
|
|
19
|
+
|
|
20
|
+
<p>Override the timeout to 1 min for a particular API call</p>
|
|
21
|
+
<pre class="code">
|
|
22
|
+
NLWS.xml.pushDown({ timeout: 60000 }).xtkBuilder.installPackage(dom);
|
|
23
|
+
</pre>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: page
|
|
3
|
+
title: The Transport Protocol
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<p>The SDK uses <b>axios</b> library internally to perform HTTP calls. This can be customized and one can use any other (async) protocol, which is implemented in the <b>transport.js</b> file.</p>
|
|
7
|
+
<p>The transport protocol defines</p>
|
|
8
|
+
<ul>
|
|
9
|
+
<li>What is an HTTP request</li>
|
|
10
|
+
<li>What is the corresponding response</li>
|
|
11
|
+
<li>How errors are handled</li>
|
|
12
|
+
</ul>
|
|
13
|
+
|
|
14
|
+
<p>The transport protocol exports a single asynchronous function <b>request</b> which takes two parameters.</p>
|
|
15
|
+
|
|
16
|
+
<p>The first parameter is the request object with the following attributes. Note that it matches axios requests.</p>
|
|
17
|
+
|
|
18
|
+
<ul>
|
|
19
|
+
<li><b>method</b> is the HTTP verb</li>
|
|
20
|
+
<li><b>url</b> is the URL to call</li>
|
|
21
|
+
<li><b>headers</b> is an object containing key value pairs with http headers and their values</li>
|
|
22
|
+
<li><b>data</b> is the request payload</li>
|
|
23
|
+
|
|
24
|
+
</ul>
|
|
25
|
+
|
|
26
|
+
<p>The second parameter is an set of additional parameters that have been pushed down to the transport layer (see the <b>Pushdown</b> paragraph for more details). In particular, the <b>timeout</b> parameter should be honored by the transport layer.</p>
|
|
27
|
+
|
|
28
|
+
<p>If the request is successful, a promise is returned with the result payload, as a string.</p>
|
|
29
|
+
|
|
30
|
+
<p>If the request fails, the promise is rejected with an error object with class <b>HttpError</b>, a litteral with the following attributes:</p>
|
|
31
|
+
<ul>
|
|
32
|
+
<li><b>statusCode</b> is the HTTP status code, such as 404, 500, etc.</li>
|
|
33
|
+
<li><b>statusText</b> is the HTTP status text coming with the error</li>
|
|
34
|
+
<li><b>data</b> is the response data, if any</li>
|
|
35
|
+
</ul>
|
|
36
|
+
|
|
37
|
+
<p>For proper error handling by the ACC SDK, it's important that the actual class of returned objects is named <b>HttpError</b></p>
|
|
38
|
+
|
|
39
|
+
<p>The transport can be overriden by using the <b>client.setTransport</b> call and passing it a transport function, i.e. an async function which</p>
|
|
40
|
+
|
|
41
|
+
<ul>
|
|
42
|
+
<li>Takes a <b>Request</b> object litteral as a parameter</li>
|
|
43
|
+
<li>Returns a the request result in a promise</li>
|
|
44
|
+
<li>Returns a rejected promise containing an <b>HttpError</b> in case of failure</li>
|
|
45
|
+
</ul>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: page
|
|
3
|
+
title: Troubleshooting
|
|
4
|
+
---
|
|
5
|
+
<p>In the version 1.1.5 of the SDK, we are automatically adding the SOAP method name in the URL in order to simplify troubleshooting. Normally, all SOAP method calls are make to the soaprouter.jsp endpoint, which makes it difficult to understand which actual API call is being made.
|
|
6
|
+
In fact the SOAP call name is available via the SOAPAction HTTP header, but it's usually not immediatelly visible.</p>
|
|
7
|
+
|
|
8
|
+
<p>The SOAP calls URLs are now formed like this: <b>http://acc-sdk:8080/nl/jsp/soaprouter.jsp?xtk:queryDef:ExecuteQuery</b> where the SOAP method name is added as a query parameter. Campaign server ignores this parameter.</p>
|
|
9
|
+
|
|
10
|
+
<p>This can be disabled using the <b>noMethodInURL</b> connection parameter</p>
|
|
11
|
+
|
|
12
|
+
<pre class="code">
|
|
13
|
+
const connectionParameters = sdk.ConnectionParameters.ofUserAndPassword(
|
|
14
|
+
"https://myInstance.campaign.adobe.com",
|
|
15
|
+
"admin", "admin",
|
|
16
|
+
{ noMethodInURL: true });
|
|
17
|
+
</pre>
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: page
|
|
3
|
+
title: Writing Documentation
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<p>
|
|
7
|
+
The documentation of the SDK is written in HTML and uses <a href="https://jekyllrb.com/">Jekyll</a>
|
|
8
|
+
and <a href="https://pages.github.com/">Github pages</a> to publish the web site.
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<h1>Setting up the local environment (MacOS)</h1>
|
|
12
|
+
|
|
13
|
+
<p>First, install <b>Ruby</b>. Do not use the default ruby install and setup a proper ruby env using <b>chruby</b> and <b>ruby-install</b></p>
|
|
14
|
+
|
|
15
|
+
<pre class="code">
|
|
16
|
+
brew install chruby ruby-install
|
|
17
|
+
ruby-install ruby
|
|
18
|
+
|
|
19
|
+
# You may have to start a new terminal for the following to work
|
|
20
|
+
|
|
21
|
+
echo "source $(brew --prefix)/opt/chruby/share/chruby/chruby.sh" >> ~/.bash_profile
|
|
22
|
+
echo "source $(brew --prefix)/opt/chruby/share/chruby/auto.sh" >> ~/.bash_profile
|
|
23
|
+
echo "chruby ruby-3.1.2" >> ~/.bash_profile # run 'chruby' to see actual version
|
|
24
|
+
|
|
25
|
+
ruby -v
|
|
26
|
+
</pre>
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
<p>Then install <b>bundler</b>, a dependency manager for Ruby.</p>
|
|
30
|
+
|
|
31
|
+
<pre class="code">
|
|
32
|
+
gem install bundler
|
|
33
|
+
</pre>
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
<p>Test the documentation site. Everything is available in the <b>docs</b> folder</p>
|
|
38
|
+
|
|
39
|
+
<pre class="code">
|
|
40
|
+
cd docs
|
|
41
|
+
bundle install
|
|
42
|
+
bundle exec jekyll serve
|
|
43
|
+
|
|
44
|
+
# visit it at http://127.0.0.1:4000
|
|
45
|
+
</pre>
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
<h1>Add a page</h1>
|
|
51
|
+
|
|
52
|
+
<p>
|
|
53
|
+
To add a documentation page, you first need to add the page to the navigation menu. The menu is defined as a yaml
|
|
54
|
+
file in <b>docs/_data/navigation.yml</b>.
|
|
55
|
+
</p>
|
|
56
|
+
|
|
57
|
+
<p>
|
|
58
|
+
Edit this file and add your entry where you want. Make sure it is in the right section, the SDK documentation,
|
|
59
|
+
or the Campaign documentation or advanced topics. Each entry has a name, which will be displayed in the navigation
|
|
60
|
+
menu, and the corresponding link to an html page containing the documentation.
|
|
61
|
+
</p>
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
<pre class="code">
|
|
65
|
+
- name: Troubleshooting
|
|
66
|
+
link: troubleshooting.html
|
|
67
|
+
- name: --
|
|
68
|
+
- name: Documentation
|
|
69
|
+
link: documentation.html
|
|
70
|
+
children:
|
|
71
|
+
- name: Connecting to Campaign
|
|
72
|
+
link: connecting.html<span class="emphasis">
|
|
73
|
+
- name: My new page
|
|
74
|
+
link: myPage.html</span>
|
|
75
|
+
- name: Concepts
|
|
76
|
+
link: concepts.html
|
|
77
|
+
</pre>
|
|
78
|
+
<p class="caption">Adding page menu in the SDK documentation</p>
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
<p>
|
|
82
|
+
Now you can create the HTML file for the page. Make sure you set the layout to <b>page</b> and give an appropriate
|
|
83
|
+
title in the file header (called the Jekyll front matter)
|
|
84
|
+
</p>
|
|
85
|
+
|
|
86
|
+
<pre class="code">
|
|
87
|
+
---
|
|
88
|
+
<span class="emphasis">layout: page</span>
|
|
89
|
+
title: My new page
|
|
90
|
+
---
|
|
91
|
+
<p>Hello, I'm a new page</p>
|
|
92
|
+
</pre>
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
<h1>CSS reference</h1>
|
|
99
|
+
|
|
100
|
+
<p>
|
|
101
|
+
A very simple CSS is used, defined in <b>assets/css/styles.css</b>
|
|
102
|
+
</p>
|
|
103
|
+
|
|
104
|
+
<h2>Headers</h2>
|
|
105
|
+
<p>
|
|
106
|
+
Use the <h1> and <h2> elements for titles. Documentation pages should be short, and you should not use deeply nested headers
|
|
107
|
+
</p>
|
|
108
|
+
|
|
109
|
+
<pre class="code">
|
|
110
|
+
<h1>I'm a H1 header</h1>
|
|
111
|
+
<h2>I'm a H2 header</h2>
|
|
112
|
+
</pre>
|
|
113
|
+
|
|
114
|
+
<div class="doc-example">
|
|
115
|
+
<h1>I'm a H1 header</h1>
|
|
116
|
+
<h2>I'm a H2 header</h2>
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
<h2>Paragraphs</h2>
|
|
121
|
+
<p></p>
|
|
122
|
+
<ul>
|
|
123
|
+
<li>Use the <p> element for all text paragraph</li>
|
|
124
|
+
<li>Use the <b>info</b> class to format a paragraph as an information notice</li>
|
|
125
|
+
<li>Use the <b>warning</b> class to format a paragraph as an warning notice</li>
|
|
126
|
+
<li>Use the <b>caption</b> class to format a paragraph as a caption to an image or a code block</li>
|
|
127
|
+
<li>Use the <b>ref</b> class to format a paragraph as reference to another part of the documentation or an external site</li>
|
|
128
|
+
</ul>
|
|
129
|
+
<p></p>
|
|
130
|
+
|
|
131
|
+
<pre class="code">
|
|
132
|
+
<p>I'm a simple paragraph with no additional CSS class</p>
|
|
133
|
+
<p class="info">I'm an information notice</p>
|
|
134
|
+
<p class="warning">I'm an warning notice</p>
|
|
135
|
+
<p class="caption">I'm a caption notice</p>
|
|
136
|
+
<p class="ref">I'm a reference to the <a href="https://github.com/adobe/acc-js-sdk">ACC JS SDK</a></p>
|
|
137
|
+
</pre>
|
|
138
|
+
|
|
139
|
+
<div class="doc-example">
|
|
140
|
+
<p>I'm a simple paragraph with no additional CSS class</p>
|
|
141
|
+
<p class="info">I'm an information notice</p>
|
|
142
|
+
<p class="warning">I'm an warning notice</p>
|
|
143
|
+
<p class="caption">I'm a caption notice</p>
|
|
144
|
+
<p class="ref">I'm a reference to the <a href="https://github.com/adobe/acc-js-sdk">ACC JS SDK</a></p>
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
<h2>Code snippets</h2>
|
|
150
|
+
|
|
151
|
+
<p>
|
|
152
|
+
Use the <pre class="code"> element to display code, scripts, etc.
|
|
153
|
+
</p>
|
|
154
|
+
|
|
155
|
+
<pre class="code">
|
|
156
|
+
<pre class="code">
|
|
157
|
+
const greetings = "Hello, world";
|
|
158
|
+
console.log(greetings);
|
|
159
|
+
</pre>
|
|
160
|
+
</pre>
|
|
161
|
+
|
|
162
|
+
<div class="doc-example">
|
|
163
|
+
<pre class="code">
|
|
164
|
+
const greetings = "Hello, world";
|
|
165
|
+
console.log(greetings);
|
|
166
|
+
</pre>
|
|
167
|
+
</div>
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
<h2>Emphasis</h2>
|
|
174
|
+
<p></p>
|
|
175
|
+
<ul>
|
|
176
|
+
<li>Use the <b> element to emphasis text in paragraphs</li>
|
|
177
|
+
<li>Use the <span class="emphasis"> element to highlight a particular section of code in a <pre block</li>
|
|
178
|
+
<li>Use the <span class="comment"> element to darken a particular section of code in a <pre block (like a comment)</li>
|
|
179
|
+
</ul>
|
|
180
|
+
<p></p>
|
|
181
|
+
|
|
182
|
+
<pre class="code">
|
|
183
|
+
<p>I'm a simple paragraph with an <b>important</b> word</p>
|
|
184
|
+
|
|
185
|
+
<pre class="code">
|
|
186
|
+
const greetings = "I'm a code block with <span class="emphasis">important</span> text";
|
|
187
|
+
console.log(greetings);
|
|
188
|
+
</pre>
|
|
189
|
+
<pre class="code">
|
|
190
|
+
const greetings = "Hello, world"; <span class="comment">// I'm a comment</span>
|
|
191
|
+
console.log(greetings);
|
|
192
|
+
</pre>
|
|
193
|
+
</pre>
|
|
194
|
+
|
|
195
|
+
<div class="doc-example">
|
|
196
|
+
<p>I'm a simple paragraph with an <b>important</b> word</p>
|
|
197
|
+
|
|
198
|
+
<pre class="code">
|
|
199
|
+
const greetings = "I'm a code block with <span class="emphasis">important</span> text";
|
|
200
|
+
console.log(greetings);
|
|
201
|
+
</pre>
|
|
202
|
+
<p></p>
|
|
203
|
+
<pre class="code">
|
|
204
|
+
const greetings = "Hello, world"; <span class="comment">// I'm a comment</span>
|
|
205
|
+
console.log(greetings);
|
|
206
|
+
</pre>
|
|
207
|
+
|
|
208
|
+
</div>
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: page
|
|
3
|
+
title: XML <=> JSON
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<p>
|
|
7
|
+
In general, XML to JSON conversion is a tricky problem. In the case of Campaign, it's even trickier since the structure
|
|
8
|
+
of the XML documents is defined by Campaign, and is therefore imposed.
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
<h1>Converting collections (arrays)</h1>
|
|
14
|
+
|
|
15
|
+
<p>
|
|
16
|
+
In Campaign, collections of objects are represented by multiple XML elements. There isn't generally a containing element.
|
|
17
|
+
For instance in the example below, we have books. Books have an author and chapters.
|
|
18
|
+
</p>
|
|
19
|
+
|
|
20
|
+
<pre class="code">
|
|
21
|
+
&book title="A confederacy of dunces">
|
|
22
|
+
&author>John Kennedy Toole&/author>
|
|
23
|
+
&chapter name="Chapter I" pages="20">
|
|
24
|
+
&/chapter>
|
|
25
|
+
&chapter name="Chapter II" pages="34">
|
|
26
|
+
&/chapter>
|
|
27
|
+
&/book>
|
|
28
|
+
</pre>
|
|
29
|
+
|
|
30
|
+
<p>
|
|
31
|
+
As you can see, there is one "author" element and two "chapter" elements. But can there be multiple author elements?
|
|
32
|
+
Well it depends, and this depends on the schema, whether the schema author has decided that "author" is a single
|
|
33
|
+
element or can be a collection (unbound="true").
|
|
34
|
+
But looking a the XML only, it's impossible to tell. We're going to assume that the author here is not a collection,
|
|
35
|
+
it is simply a string property that has been implemented as an XML element and not as an XML attribute. The corresponding
|
|
36
|
+
SimpleJson will be the following.
|
|
37
|
+
</p>
|
|
38
|
+
|
|
39
|
+
<pre class="code">
|
|
40
|
+
{ "$author": "John Kennedy Toole",
|
|
41
|
+
"chapter": [
|
|
42
|
+
{
|
|
43
|
+
"name": "Chapter I",
|
|
44
|
+
"pages": 20
|
|
45
|
+
}, {
|
|
46
|
+
"name": "Chapter II",
|
|
47
|
+
"pages”: 3
|
|
48
|
+
},
|
|
49
|
+
] }
|
|
50
|
+
</pre>
|
|
51
|
+
|
|
52
|
+
<p>
|
|
53
|
+
So far, so good, but what if the book only had one chapter?
|
|
54
|
+
</p>
|
|
55
|
+
|
|
56
|
+
<pre class="code">
|
|
57
|
+
&book title="A confederacy of dunces">
|
|
58
|
+
&author>John Kennedy Toole&/author>
|
|
59
|
+
&chapter name="Chapter I" pages="20">
|
|
60
|
+
&/chapter>
|
|
61
|
+
&/book>
|
|
62
|
+
</pre>
|
|
63
|
+
|
|
64
|
+
<p>
|
|
65
|
+
This becomes trickier because now we have two alternatives: in JSON the "chapter" property can be
|
|
66
|
+
either an array of one element (which is what is expected) or the element itself
|
|
67
|
+
</p>
|
|
68
|
+
|
|
69
|
+
<pre class="code">
|
|
70
|
+
{ "$author": "John Kennedy Toole",
|
|
71
|
+
"chapter": [
|
|
72
|
+
{
|
|
73
|
+
"name": "Chapter I",
|
|
74
|
+
"pages": 20
|
|
75
|
+
] }
|
|
76
|
+
|
|
77
|
+
<span class="comment">// or</span>
|
|
78
|
+
|
|
79
|
+
{ "$author": "John Kennedy Toole",
|
|
80
|
+
"chapter": {
|
|
81
|
+
"name": "Chapter I",
|
|
82
|
+
"pages": 20
|
|
83
|
+
} }
|
|
84
|
+
</pre>
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
<p>
|
|
88
|
+
And what if a particular book has no chapters? There will not even be any <chapter> elements in the XML. How can
|
|
89
|
+
the SDK decide if it should create an empty chapters array or leave the chapter property undefined.
|
|
90
|
+
</p>
|
|
91
|
+
|
|
92
|
+
<p>
|
|
93
|
+
This is really painful from a user point of view at it can lead to complex and error prone code: every time a
|
|
94
|
+
JSON property is accessed, one has to wonder what type it is and whether it is the right type
|
|
95
|
+
</p>
|
|
96
|
+
|