| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> |
| <html> |
| <head> |
| <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> |
| <title>Source Writing Transformer</title> |
| <link href="http://purl.org/DC/elements/1.0/" rel="schema.DC"> |
| <meta content="Jeremy Quinn" name="DC.Creator"> |
| <meta content="This document describes the Source Writing transformer of Cocoon." name="DC.Description"> |
| </head> |
| <body> |
| |
| <h1>Source Writing Transformer</h1> |
| |
| <p>Diverts xml from a pipeline, writing it to a Source (or |
| deleting it).</p> |
| |
| <p>Thankfully, <span class="codefrag">FileSource</span> is no longer the only <span class="codefrag">Source</span> that currently implements <span class="codefrag">WritableSource</span>; there are implementations of WebDAV and Apache Slide WritableSources in the scratchpad. Hopefully further <span class="codefrag">ModifiableSource</span> implementations (XMLDB, CVS, Email, SQL, etc.) will be appear in the future.</p> |
| |
| <p>See the transformer in action with the Cocoon Samples for webdav block, |
| and Wiki about it at |
| <a class="external" href="http://wiki.apache.org/cocoon/WebDAVCMS">WebDAVCMS</a>. |
| </p> |
| |
| <ul> |
| |
| <li>Name : write-source</li> |
| |
| <li>Class: org.apache.cocoon.transformation.SourceWritingTransformer</li> |
| |
| <li>Cacheable: no.</li> |
| |
| </ul> |
| |
| |
| <h1>The Tags</h1> |
| |
| <pre class="code"> |
| |
| <source:write> |
| [<source:path/>] |
| <source:source/> |
| <source:fragment/> |
| </source:write> |
| |
| <source:insert/> |
| <source:path/> |
| <source:source/> |
| <source:fragment/> |
| [<source:replace/>] |
| [<source:reinsert/>] |
| </source:insert> |
| |
| <source:delete/> |
| <source:source/> |
| [<source:path/>] - Ignored |
| [<source:fragment/>] - Ignored |
| [<source:replace/>] - Ignored |
| [<source:reinsert/>] - Ignored |
| </source:insert> |
| |
| </pre> |
| |
| <p>In the namespace <span class="codefrag">xmlns:source="http://apache.org/cocoon/source/1.0"</span>.</p> |
| |
| <p>The contents of the <span class="codefrag"><source:fragment/></span> |
| tag are written to the specified ModifiableSource when the |
| document containing it is transformed by SourceWritingTransformer |
| (or deleted if you are using the <span class="codefrag">delete </span>instruction).</p> |
| |
| |
| <h1>Definition</h1> |
| |
| <pre class="code"> |
| |
| <map:transformer name="write-source" |
| src="org.apache.cocoon.transformation.SourceWritingTransformer"> |
| <map:parameter name="serializer" value="xml"/> |
| </map:transformer/> |
| |
| </pre> |
| |
| <p>The SourceWritingTransformer is predefined for you in the main SiteMap.</p> |
| |
| |
| <h1>Invocation</h1> |
| |
| <p>This invokes the SourceWritingTransformer on your pipeline.</p> |
| |
| <pre class="code"> |
| |
| <map:transform type="write-source"/> |
| |
| </pre> |
| |
| <p>Or you can over-ride the default serializer here.</p> |
| |
| <pre class="code"> |
| |
| <map:transform type="write-source"> |
| <map:parameter name="serializer" value="my-special-serializer"/> |
| </map:transform> |
| |
| </pre> |
| |
| |
| |
| <h1>The Tags in detail</h1> |
| |
| <h2>source:write</h2> |
| <p>The source:write tag can take optional attributes, <span class="codefrag">create</span> (defaults to 'true') and <span class="codefrag">serializer</span> (defaults to the serializer set up in the definition or invocation of the transformer).</p> |
| <p>Replaces the entire content of a <span class="codefrag">Source</span> (specified by the <span class="codefrag"><source:source/></span> tag) with the contents of the <span class="codefrag"><source:fragment/></span> tag, if @create is 'true', a new asset will be created if one does not already exist.</p> |
| <p>The <span class="codefrag"><source:source/></span> and <span class="codefrag"><source:fragment/></span> tags are required, a <span class="codefrag"><source:path/></span> tag is optional, if specified, the value is used as an XPath to generate xml in your <span class="codefrag">Source</span>, in which to wrap your content.</p> |
| <h3>source:source</h3> |
| <p>The System ID of the <span class="codefrag">Source</span> to be written to.</p> |
| <p>e.g. <span class="codefrag"><source:source>docs/blah.xml</source:source></span> or <span class="codefrag"><source:source>context:/blah.xml</source:source></span> etc.</p> |
| <h3>source:fragment</h3> |
| <p>The XML Fragment to be written.</p> |
| <p>For example:</p> |
| <pre class="code"> |
| |
| <source:fragment><foo> |
| <bar id="dogcow"/> |
| </foo></source:fragment> |
| |
| </pre> |
| <p>or</p> |
| <pre class="code"> |
| |
| <source:fragment> |
| <foo/> |
| <bar> |
| <dogcow/> |
| <bar/> |
| </source:fragment> |
| |
| </pre> |
| <p>etc.</p> |
| <div class="note">The second example type, can only be used when the <span class="codefrag"><source:path/></span> tag has been specified.</div> |
| <h3>source:path</h3> |
| <p>[Optional] XPath to specify how your content is wrapped</p> |
| <p>e.g. <span class="codefrag"><source:path>doc</source:path></span> - your content is placed inside a <span class="codefrag"><doc/></span> root tag.</p> |
| <div class="note">If this parameter is omitted, your content MUST have only ONE top-level node.</div> |
| |
| |
| <h2>source:insert</h2> |
| <p>The source:insert tag can take optional attributes, <span class="codefrag">create</span> (defaults to 'true') and <span class="codefrag">serializer</span> (defaults to the serializer set up in the definition or invocation of the transformer).</p> |
| <p>Inserts into a <span class="codefrag">Source</span> (specified by the <span class="codefrag"><source:source/></span> tag) the contents of the tag <span class="codefrag"><source:fragment/></span> at the XPath location specified in the <span class="codefrag"><source:path/></span> tag, if @create is 'true', a new <span class="codefrag">Source</span> will be created if one does not already exist.</p> |
| <p>The <span class="codefrag"><source:source/></span>, <span class="codefrag"><source:path/></span> and <span class="codefrag"><source:fragment/></span> tags are all required, the <span class="codefrag"><source:replace/></span> and <span class="codefrag"><source:reinsert/></span> tags are optional.</p> |
| <h3>source:source</h3> |
| <p>The System ID of the <span class="codefrag">Source</span> to be inserted into.</p> |
| <p>e.g. <span class="codefrag"><source:source>docs/blah.xml</source:source></span> or <span class="codefrag"><source:source>context:/blah.xml</source:source></span> etc.</p> |
| <h3>source:fragment</h3> |
| <p>The XML Fragment to be written.</p> |
| <p>e.g.</p> |
| <pre class="code"> |
| |
| <source:fragment> |
| <foo> |
| <bar id="dogcow"/> |
| </foo> |
| </source:fragment> |
| |
| </pre> |
| <p>or</p> |
| <pre class="code"> |
| |
| <source:fragment> |
| <foo/> |
| <bar> |
| <dogcow/> |
| <bar/> |
| </source:fragment> |
| |
| </pre> |
| <p>etc.</p> |
| <h3>source:path</h3> |
| <p></p> |
| <h3>source:replace</h3> |
| <p>[Optional] XPath (from <span class="codefrag"><source:path/></span>) to select the node that is replaced by your new content</p> |
| <p>e.g. <span class="codefrag"><source:replace>foo/bar/dogcow/@status='cut'</source:replace></span> (is equivalent to this in XSLT: <span class="codefrag">select="foo[bar/dogcow/@status='cut']"</span>), what gets replaced is the <span class="codefrag"><foo/></span> which has a <span class="codefrag"><bar/></span> with a <span class="codefrag"><dogcow status="cut"/></span> in it.</p> |
| <p>The <span class="codefrag">overwrite</span> attribute of the parent <span class="codefrag"><source:insert/></span> is used to check if replacing is allowed. If <span class="codefrag">overwrite</span> is 'true' (the default) the node is replaced. If <span class="codefrag">overwrite</span> is 'false' the node is only inserted if the replace node is found.</p> |
| <h3>source:reinsert</h3> |
| <p>[Optional] The XPath (relative to <span class="codefrag"><source:replace/></span>) to backup the contents of the overwritten node to.</p> |
| <p>e.g. <span class="codefrag"><source:reinsert>foo/versions</source:reinsert></span> or <span class="codefrag"><source:reinsert>/doc/versions/foo</source:reinsert></span>.</p> |
| <p>If specified and a node is replaced, all children of this replaced node will be reinserted at the given path.</p> |
| |
| <h2>Notes</h2> |
| <ul> |
| |
| <li>if 'replace' is not specified, your 'fragment' is appended as a child of 'path'.</li> |
| |
| <li>if 'replace' is specified and it exists and 'overwrite' is true, your 'fragment' is inserted in 'path', before 'replace' and then 'replace' is deleted.</li> |
| |
| <li>if 'replace' is specified and it exists and 'overwrite' is false, no action occurs.</li> |
| |
| <li>if 'replace' is specified and it does not exist and 'overwrite' is true, your 'fragment' is appended as a child of 'path'.</li> |
| |
| <li>if 'replace' is specified and it does not exist and 'overwrite' is false, your 'fragment' is appended as a child of 'path'.</li> |
| |
| <li>if 'reinsert' is specified and it does not exist, no action occurs.</li> |
| |
| </ul> |
| |
| <h2>source:delete</h2> |
| <p>This instruction takes only a <span class="codefrag"><source:source/></span> |
| parameter (as a child tag) and deletes the corresponding |
| source. All other <span class="codefrag">source:*</span> tags are ignored, if |
| present: this allows for easy source-write instructions to be |
| generated on the fly (e.g. by a stylesheet). Just change |
| <span class="codefrag">source:write</span> to <span class="codefrag">source:delete</span> and |
| you're set. |
| </p> |
| |
| |
| |
| <h1>Examples</h1> |
| |
| <h2>Simple Write</h2> |
| <pre class="code"> |
| |
| <page> |
| ... |
| <source:write xmlns:source="http://apache.org/cocoon/source/1.0"> |
| <source:source>context://doc/editable/my.xml</source:source> |
| <source:fragment><page> |
| <title>Hello World</title> |
| <content> |
| <p>This is my first paragraph.</p> |
| </content> |
| </page></source:fragment> |
| </source:write> |
| ... |
| </page> |
| |
| </pre> |
| |
| <h2>Insert at end</h2> |
| <pre class="code"> |
| |
| <page> |
| ... |
| <source:insert xmlns:source="http://apache.org/cocoon/source/1.0"> |
| <source:source>context://doc/editable/my.xml</source:source> |
| <source:path>page/content</source:path> |
| <source:fragment> |
| <p>This paragraph gets <emp>inserted</emp>.</p> |
| <p>With this one, at the end of the content.</p> |
| </source:fragment> |
| </source:insert> |
| ... |
| </page> |
| |
| </pre> |
| |
| <h2>Replace</h2> |
| <pre class="code"> |
| |
| <page> |
| ... |
| <source:insert xmlns:source="http://apache.org/cocoon/source/1.0"> |
| <source:source>context://doc/editable/my.xml"</source:source> |
| <source:path>page/content</source:path> |
| <source:replace>p[1]</source:replace> |
| <source:fragment> |
| <p>This paragraph <emp>replaces</emp> the first paragraph.</p> |
| </source:fragment> |
| </source:insert> |
| ... |
| </page> |
| |
| </pre> |
| |
| <h2>Insert at the beginning</h2> |
| <pre class="code"> |
| |
| <page> |
| ... |
| <source:insert> |
| <source:source>context://doc/editable/my.xml</source:source> |
| <source:path>page</source:path> |
| <source:replace>content</source:replace> |
| <source:reinsert>content</source:reinsert> |
| <source:fragment> |
| <content> |
| <p>This new paragraph gets inserted <emp>before</emp> the other ones.</p> |
| </content> |
| </source:fragment> |
| <source:insert> |
| ... |
| </page> |
| |
| </pre> |
| <p>This sample does not currently work, see the tests in the scratchpad at <span class="codefrag">http://localhost:8080/cocoon/mount/editor/tests</span>.</p> |
| <div class="note">You must have built Cocoon with the scratchpad included for this link to work.</div> |
| |
| <h2>Delete a source</h2> |
| <pre class="code"> |
| |
| <page> |
| ... |
| <source:delete> |
| <source:source>context://doc/editable/my.xml</source:source> |
| <source:delete> |
| ... |
| </page> |
| |
| </pre> |
| |
| <h2>Sample of the output of these tags</h2> |
| <p>This is the kind of information that the <span class="codefrag">SourceWritingTransformer</span> outputs to the pipeline, replacing the original <span class="codefrag">source:write</span> and <span class="codefrag">source:insert</span> tags</p> |
| <pre class="code"> |
| |
| <page> |
| ... |
| <sourceResult> |
| <action>new|overwritten|none</action> |
| <behaviour>write|insert<behaviour> |
| <execution>success|failure</execution> |
| <serializer>xml</serializer> |
| <source>source:specific/path/to/context/doc/editable/my.xml</source> |
| <message>a message about what happened</message> |
| </sourceResult> |
| ... |
| </page> |
| |
| </pre> |
| |
| |
| <h1>Known Problems</h1> |
| |
| <p>I cannot get the 'insert before' example working, which uses the <span class="codefrag"><source:reinsert/></span> tag.</p> |
| |
| |
| <h1>Warning</h1> |
| |
| <p>It is not known how robust this transformer is under even moderate load, especially when it comes to more than one person modifying the same file at the same time.</p> |
| |
| |
| </body> |
| </html> |