Automation
Automation

Scripting How-To: Excerpt on the <xsl:document> instruction element

by Cordelia on ‎08-09-2015 07:27 AM - edited on ‎09-15-2017 04:22 PM by Administrator Administrator (1,458 Views)

 

Overview

 

This element is used to output XML, HTML, or text to an output file. This applies to SLAX version 1.0 and higher.

 

Feature

 

While the XSLT 1.1 standard was never finalized, libxslt adopted some parts of it anyway, including the <xsl:document> instruction element, which later came to be known as <xsl:result-document> in XSLT 2.0. This element is used to output XML, HTML, or text to an output file. Internal to libxslt (and therefore, to Junos OS), it shares code with four other extension elements:

 <exsl:document>, <redirect:write>, <saxon:output>, and <xt:document>

so when we added append support to <redirect:write> in Junos OS Release 11.1, we actually added it to all five elements. I would recommend that script writers use <xsl:document> rather than <redirect:write> because there is no need to include an extension namespace for XSLT elements.

 

Syntax

 

1	<xsl:document append="yes|no" doctype-public="string" doctype-system="string"
2	             encoding="format" href="filename" indent="yes|no" method="html|text|xml"
3	             omit-xml-declaration="yes|no" standalone="yes|no" version="string" > {
4	   File content...
5	}

Description

 

The <xsl:document> instruction element writes data to an output file on the local disk drive in XML, HTML, or text format. The filename is indicated through the required href attribute which, like all the other attributes of <xsl:document> is handled as an attribute value template, so its value can be specified as a hardcoded string, a variable, or an XPath expression.

 

It is recommended that the full path to the output file be provided because, while the default directory for op scripts and commit scripts is /var/tmp, the default directory at times for event scripts is the root directory /, which cannot be written to by <xsl:document>. The only allowed URI scheme for the filename is "file", and it can be included as part of the href attribute value but is not required, and there is no difference in behavior if it is not included (e.g., href="file:///var/tmp/output").

 

The <xsl:document> element can only write to the local disk. Writing via networking protocols such as FTP or HTTP is not supported, and neither is writing to other routing engines. Also, the full path specified in the href attribute must already exist; because the script processor in Junos OS does not create new directories as part of the <xsl:document> operation.

 

The <xsl:document> element can only write to the local disk. Writing via networking protocols such as FTP or HTTP is not supported, and neither is writing to other routing engines. Also, the full path specified in the href attribute must already exist; because the script processor in Junos OS does not create new directories as part of the <xsl:document> operation.

 

All contents of the <xsl:document> element are written to the output file.

 

Code example:

 

1	<xsl:document href="/var/tmp/example-file" indent="yes"> {
2	   <chassis> {
3	      <name> "M40e";
4	      <name> "EX8216";
5	   }
6	}

 

Output File:

 

1	<?xml version="1.0"?>
2	<chassis>
3	 <name>M40e</name>
4	 <name>EX8216</name>
5	</chassis>

 

The method attribute can be set to xml, html, or text and determines the format for the output file. The default method is xml, unless the root element of the output file is <html>, in which case the default method is html.  When method is set to text, all of the text content is output, without any escaping or extra indenting.

 

Code Example:

 

01	var $content = {
02	   <html> {
03	      <head> {
04	         <title> "Example HTML";
05	      }
06	      <body> {
07	         expr "First Line";
08	         <br>;
09	         expr "Second Line";
10	      }
11	   }
12	}
13	<xsl:document href="/var/tmp/xml-method" method="xml" indent="yes"> {
14	   copy-of $content;
15	}
16	<xsl:document href="/var/tmp/html-method" method="html"> {
17	   copy-of $content;
18	}
19	<xsl:document href="/var/tmp/text-method" method="text"> {
20	   copy-of $content;
21	}

Output Files:

 

01	jnpr@srx210> file show /var/tmp/xml-method
02	<?xml version="1.0"?>
03	<html>
04	 <head>
05	   <title>Example HTML</title>
06	 </head>
07	 <body>First Line<br/>Second Line</body>
08	</html>
09	  
10	jnpr@srx210> file show /var/tmp/html-method
11	<html>
12	<head>
13	<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
14	<title>Example HTML</title>
15	</head>
16	<body>First Line<br>Second Line</body>
17	</html>
18	 
19	jnpr@srx210> file show /var/tmp/text-method
20	Example HTMLFirst LineSecond Line

By default, the <xsl:document> element overwrites the output file if it already exists; however, if the append attribute, which was added in Junos OS Release 11.1, is set to either "yes" or "true", then the new data will be appended to the file, leaving the existing file contents in place. If append is set to "yes" or "true" when writing using the "xml" method, then the XML declaration is never added, even if the file is being created; however, at the time of this writing, if append is included and is not set to "yes" or "true" then the XML declaration is always added, even if omit-xml-declaration is set to "yes", so it is best to only include the append attribute if it is being enabled, especially since it is off by default.

 

Code Example:

 

1	<xsl:document href="/var/tmp/time-record" method="text"> {
2	    expr date:date-time() _ "\n";
3	}
4	<xsl:document href="/var/tmp/time-record" method="text" append="yes"> {
5	    expr date:date-time() _ "\n";
6	}

Output File:

 

1	2011-04-23T21:11:31Z
2	2011-04-23T21:11:31Z

 

A large caveat exists when using <xsl:document>: it always accesses the file system as user "nobody" group "wheel". This means that files cannot be overwritten or appended unless their permissions give write access to user "nobody", to group "wheel", or to everyone, and files cannot be created unless the directory provides similar permissions. In addition, when the <xsl:document> element creates an output file, it is owned by user "nobody" and its file permissions are 644, meaning that while anyone can read it, only user "nobody" can edit or delete it. (As of Junos OS Release 10.0R3, super-users can delete these files from the CLI.) As a workaround, create the file initially through the <file-put> RPC with permissions 666, giving everyone read and write access, and then have <xsl:document> overwrite the original file. As a result, the file will be owned by the user of the executing script and will have the desired contents as created by <xsl:document>.

 

Example Code:

 

01	var $rpc = {
02	   <get-configuration> {
03	      <configuration> {
04	         <event-options> {
05	            <destinations>;
06	         }
07	      }
08	   }
09	}
10	<xsl:document href="/var/tmp/destination-config" indent="yes"> {
11	    copy-of jcs:invoke( $rpc );
12	}

 

Output:

 

01	jnpr@srx210> file list /var/tmp/destination-config detail
02	-rw-r--r-- 1 nobody wheel      405 Apr 23 22:01 /var/tmp/destination-config
03	total 1
04	 
05	jnpr@srx210> file show /var/tmp/destination-config
06	<?xml version="1.0"?>
07	<configuration xmlns:junos="http://xml.juniper.net/junos/*/junos" junos:changed-seconds="1303539992" junos:changed-localtime="2011-04-23 06:26:32 UTC">
08	   <event-options>
09	      <destinations>
10	         <name>local</name>
11	         <archive-sites>
12	            <name>/var/tmp</name>
13	         </archive-sites>
14	      </destinations>
15	   </event-options>
16	</configuration>

 

Example Code:

 

01	var $rpc = {
02	   <get-configuration> {
03	      <configuration> {
04	         <event-options> {
05	             <destinations>;
06	         }
07	      }
08	   }
09	}
10	var $filename = "/var/tmp/destination-config";
11	var $put-rpc = {
12	   <file-put> {
13	      <filename> $filename;
14	      <permission> "666";
15	      <encoding> "ascii";
16	      <delete-if-exist>;
17	      <file-contents> "To be overwritten";
18	   }
19	}
20	var $results = jcs:invoke( $put-rpc );
21	<xsl:document href=$filename indent="yes"> {
22	   copy-of jcs:invoke( $rpc );
23	}

 

Output:

 

01	jnpr@srx210> file list /var/tmp/destination-config detail -rw-rw-rw- 1 jnpr staff 405 Apr 23 22:07 /var/tmp/destination-config
02	total 1
03	jnpr@srx210> file show /var/tmp/destination-config
04	<?xml version="1.0"?>
05	<configuration xmlns:junos="http://xml.juniper.net/junos/*/junos" junos:changed-seconds="1303539992" junos:changed-localtime="2011-04-23 06:26:32 UTC">
06	   <event-options>
07	      <destinations>
08	         <name>local</name>
09	         <archive-sites>
10	            <name>/var/tmp</name>
11	         </archive-sites>
12	      </destinations>
13	    </event-options>
14	</configuration>

The doctype-public and doctype-system attributes can be used to cause a DOCTYPE declaration to appear in the output file.

 

Code Example:

 

1	<xsl:document href="/var/tmp/output" doctype-system="local.dtd"> {
2	   <parent> {
3	      <child>;
4	      <child>;
5	      <child>;
6	   }
7	}

 

Output File:

 

1	<?xml version="1.0"?>
2	<!DOCTYPE parent SYSTEM "local.dtd"><
3	<parent><child/><child/><child/></parent>

 

The encoding attribute determines what character encoding format should be used when writing the output file. The following (case-insensitive) values can be used: ascii, html, iso-8859-1, iso-8859-2, iso-8859-3, iso-8859-4, iso-8859-5, iso-8859-6, iso-8859-7, iso-8859-8, iso-8859-9, iso-8859-10, iso-8859-11, iso-8859-13, iso-8859-14, iso-8859-15, iso-8859-16, iso-latin-1, iso-latin-2, utf8, utf-8, utf16, utf-16, utf-16le, utf-16be, and us-ascii. The default value is utf-8.

 

Code Example:

 

1	<xsl:document href="/var/tmp/output-html" encoding="html"> {
2	   <copyright> "©";
3	}

Output File:

 

1	<?xml version="1.0" encoding="html"?>
2	<copyright>&copy;</copyright>

The indent attribute can be set to either "yes" or "no", and it determines whether indentation should be performed or not. It is off by default for the "xml" method and on by default for the "html" method. It has no effect on text files.

 

Code Example:

 

01	var $content = {
02	   <interfaces> {
03	      <interface> {
04	         <name> "ge-0/0/0";
05	      }
06	   }
07	}
08	<xsl:document href="/var/tmp/output1" method="xml"> {
09	   copy-of $content;
10	}
11	<xsl:document href="/var/tmp/output2" method="xml" indent="yes"> {
12	   copy-of $content;
13	}

Output Files:

 

01	jnpr@srx210> file show /var/tmp/output1
02	<?xml version="1.0"?>
03	<interfaces><interface><name>ge-0/0/0</name></interface></interfaces>
04	 
05	jnpr@srx210> file show /var/tmp/output2
06	<?xml version="1.0"?>
07	<interfaces>
08	 <interface>
09	   <name>ge-0/0/0</name>
10	 </interface>
11	</interfaces>

An XML declaration is included by default when using the xml method (unless appending is enabled). To disable the XML declaration, set the omit-xml-declaration attribute to "yes". This attribute has no effect when using the html or text methods.

 

Code Example:

 

1	<xsl:document href="/var/tmp/output" indent="yes" omit-xml-declaration="yes"> {
2	   <details> {
3	      <script> $script;
4	      <user> $user;
5	   }
6	}

Output File:

 

1	<details>
2	 <script>test.slax</script>
3	 <user>jnpr</user>
4	</details>

By default, no standalone document declaration is included in the XML declaration, but if the standalone attribute is set to either "yes" or "no", then standalone is included in the declaration with the specified value.

 

Code Example:

 

1	<xsl:document href="/var/tmp/context" indent="yes" standalone="yes" > {
2	   copy-of $junos-context/user-context;
3	}

Output File:

 

1	<?xml version="1.0" standalone="yes"?>
2	<user-context xmlns:junos="http://xml.juniper.net/junos/*/junos">
3	 <user>jnpr</user>
4	 <class-name>j-super-user</class-name>
5	 <uid>2001</uid>
6	 <login-name>jnpr</login-

 

The version attribute is used to alter the XML version value that is written in the XML declaration of the output file when the xml method is used. It should be set to 1.0, but changing it to other values does not alter the format of the document in any way.

 

The <xsl:document> element has an additional attribute, cdata-section-elements, which is intended to indicate what nodes in the XML output file should have their text contents enclosed within CDATA sections, but it is non-functional at the time of this writing.

 

If an error occurs due to an inability to write to the output file, an incorrect attribute setting, or for some other reason, then the script fails and an error message is displayed to the script user for op scripts and commit scripts or to the event script output file. The script itself is unable to react to the error.

 

The Junos OS API contains an RPC element for writing to the disk: <file-put>, which has some capabilities that <xsl:document> does not have, including the ability to write in base64 format, to select file permissions, and to write to the non-local routing engines. In addition, unlike <xsl:document>, the <file-put> RPC access the file system using the credentials of the user that is executing the script. However, <file-put> is incapable of writing in XML or HTML format or of appending to an existing file, so when a script needs to perform one of those three operations, then <xsl:document> is an appropriate element to use.

 

Junos OS contains support for five instruction elements that have equivalent functionality:

<exsl:document>, <redirect:write>, <saxon:output>, <xsl:document>, and <xt:document>

. All attributes and functionality are common among the five elements except for some variances in support for the different file selector attributes: file, href, and select. Given that all five elements perform the same operation, it is recommended that the <xsl:document> element be used in place of the others; because, unlike the other four, it does not need to have an extension namespace defined.

 

Example

 

This op script demonstrates how to use the five file writing instruction elements.

 

Code

 

01	version 1.0;
02	ns junos = "http://xml.juniper.net/junos/*/junos";
03	ns xnm = "http://xml.juniper.net/xnm/1.1/xnm";
04	ns jcs = "http://xml.juniper.net/junos/commit-scripts/1.0";
05	ns exsl extension = "http://exslt.org/common";
06	ns saxon extension = "http://icl.com/saxon";
07	ns redirect extension = "org.apache.xalan.xslt.extensions.Redirect";
08	ns xt extension = "http://www.jclark.com/xt";
09	 
10	import "../import/junos.xsl";
11	match / {
12	   <op-script-results> {
13	      /* <redirect:write> <xsl:document> <saxon:output> and appending */
14	      var $append-file = "/var/tmp/append-example";
15	      <redirect:write href=$append-file append="yes"> {
16	        copy-of $junos-context/localtime-iso;
17	      }
18	      <xsl:document href=$append-file append="yes"> {
19	         copy-of $junos-context/localtime-iso;
20	      }
21	      <saxon:output href=$append-file append="yes"> {
22	         copy-of $junos-context/localtime-iso;
23	      }
24	 
25	      /* <exsl:document> and indenting */
26	      <exsl:document href="/var/tmp/indent-example" indent="yes"> {
27	         <chassis> {
28	            <platform> "m40e";
29	            <platform> "mx960";
30	            <platform> "ex8216";
31	         }
32	      }
33	 
34	      /* <xt:document> and text output */
35	      <xt:document href="/var/tmp/text-example" method="text"> {
36	         expr "Class-name: " _ $junos-context/user-context/class-name _ "\n";
37	         expr "User-name: " _ $junos-context/user-context/user _ "\n";
38	      }
39	   }
40	}

Output

 

01	jnpr@srx210> file list detail /var/tmp/*-example
02	-rw-r--r-- 1 nobody wheel      318 Apr 25 15:31 /var/tmp/append-example
03	-rw-r--r-- 1 nobody wheel      130 Apr 25 15:31 /var/tmp/indent-example
04	-rw-r--r-- 1 nobody wheel       41 Apr 25 15:31 /var/tmp/text-example
05	total 3
06	 
07	jnpr@srx210> file show /var/tmp/append-example
08	<localtime-iso xmlns:junos="http://xml.juniper.net/junos/*/junos">2011-04-25 15:31:44 UTC</localtime-iso>
09	<localtime-iso xmlns:junos="http://xml.juniper.net/junos/*/junos">2011-04-25 15:31:44 UTC</localtime-iso>
10	<localtime-iso xmlns:junos="http://xml.juniper.net/junos/*/junos">2011-04-25 15:31:44 UTC</localtime-iso>
11	 
12	jnpr@srx210> file show /var/tmp/indent-example
13	<?xml version="1.0"?>
14	<chassis>
15	 <platform>m40e</platform>
16	 <platform>mx960</platform>
17	 <platform>ex8216</platform>
18	</chassis>
19	 
20	jnpr@srx210> file show /var/tmp/text-example
21	Class-name: j-super-user
22	User-name: jnpr

Source

 

Original from Curtis Call blog post April. 25, 2011. Released to TechWiki with permission.