* Bug #14965 fixed: getPreferencesValue() upgraded. 46/18946/4
Samuel GOUGEON [Tue, 24 Jan 2017 16:16:59 +0000 (17:16 +0100)]
 - http://bugzilla.scilab.org/14965 :
   + tag with multiple occurrences is now supported
   + the path+filename of the XML document can now be provided
     instead of its XML handle.
 - Commit required for https://codereview.scilab.org/#/c/18803/
 - new page in PDF: http://bugzilla.scilab.org/attachment.cgi?id=4470

Change-Id: Ia8f0f0cdee1cff2e813a5cd874461aa5b7387be8

scilab/CHANGES.md
scilab/modules/preferences/help/en_US/getPreferencesValue.xml
scilab/modules/preferences/macros/getPreferencesValue.sci

index e6d333d..8cbf67d 100644 (file)
@@ -204,6 +204,7 @@ or a 3-components vector to set the position in axes coordinates to draw the dat
 * When the view property of Axes object is set at `2d`, the rotation becomes impossible.
 * The zero-pole-gain (zpk) representation added for linear dynamical systems.
 * It is now possible to add a title to the axes via the "Label -> Title" context menu entry
+* `getPreferencesValue` can now read a tag having multiple occurrences, and accepts the path to a preferences file instead of its XML handle.
 
 
 Help pages:
@@ -213,7 +214,7 @@ Help pages:
   `printf`, `sprintf`, `iconvert`, `stdev`, `xlabel`, `and_op`, `or_op`, `permute`, `tree2code`, `%helps`,
   `scilab|scilex`, `flipdim`
 * rewritten: `consolebox`, `double`, `isoview`, `pixel_drawing_mode`, `householder`, `or`, `and`, `format`, `typeof`,
-`brackets`, `setlanguage`, `sleep`, `isinf`, `bitor`, `bitxor`, `bitand`, `macr2tree`, `geomean`, `clf`
+`brackets`, `setlanguage`, `sleep`, `isinf`, `bitor`, `bitxor`, `bitand`, `macr2tree`, `geomean`, `clf`, `getPreferencesValue`
 * reorganized:
   - `else`, `elseif`, `end`, `try`, `sciargs`, `global`, `halt`, `empty`, `power`
   - `pixel_drawing_mode`, `show_window`, `twinkle`, `uigetcolor`, `winsid`, `xdel`, `xgrid`, `xname`, `xnumb`
@@ -450,6 +451,7 @@ Bug Fixes
 * [#14941](http://bugzilla.scilab.org/show_bug.cgi?id=14941): `find` did not accept encoded integers
 * [#14942](http://bugzilla.scilab.org/show_bug.cgi?id=14942): Keep the Tkscale block label if block already has label.
 * [#14956](http://bugzilla.scilab.org/show_bug.cgi?id=14956): `clf("reset")` forgot resetting the `immediate_drawing`, `resize`, `resizefcn`, `closerequestfcn`, `toolbar_visible`, `menubar_visible`, `infobar_visible`, `default_axes`, and `icon` figure properties.
+* [#14965](http://bugzilla.scilab.org/show_bug.cgi?id=14965): `getPreferencesValue` could not read a tag having multiple occurrences and did not accept the path to the preferences file.
 
 ### Bugs fixed in 6.0.0 beta-2 and earlier 6.0.0 pre-releases:
 
index c44e216..6f1e0b7 100644 (file)
@@ -2,6 +2,7 @@
 <!--
  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
  * Copyright (C) 2014 - Scilab Enterprises - Calixte DENIZET
+ * Copyright (C) 2017 - Samuel GOUGEON
  *
  * Copyright (C) 2012 - 2016 - Scilab Enterprises
  *
  * along with this program.
  *
  -->
-<refentry xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svg="http://www.w3.org/2000/svg" xmlns:ns5="http://www.w3.org/1999/xhtml" xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:db="http://docbook.org/ns/docbook" xmlns:scilab="http://www.scilab.org" xml:id="getPreferencesValue" xml:lang="en">
+<refentry xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink"
+          xmlns:svg="http://www.w3.org/2000/svg" xmlns:ns5="http://www.w3.org/1999/xhtml"
+          xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:db="http://docbook.org/ns/docbook"
+          xmlns:scilab="http://www.scilab.org" xml:id="getPreferencesValue" xml:lang="en">
     <refnamediv>
         <refname>getPreferencesValue</refname>
-        <refpurpose>Get preferences value</refpurpose>
+        <refpurpose>Parses and gets values of chosen tags attributes in a XML file of preferences</refpurpose>
     </refnamediv>
     <refsynopsisdiv>
         <title>Syntax</title>
         <synopsis>
-            getPreferencesValue(xpath, attributes [, doc])
+            Values = getPreferencesValue(path2tag, attributes)
+            Values = getPreferencesValue(path2tag, attributes, XMLsource)
         </synopsis>
     </refsynopsisdiv>
     <refsection>
         <title>Arguments</title>
         <variablelist>
             <varlistentry>
-                <term>xpath</term>
+                <term>path2tag</term>
                 <listitem>
-                    <para>a string, represents the XPath request to get the node in the preferences file.</para>
+                    <para>
+                        unique string: in the XML source file, path targeting a chosen tag whose
+                        attributes must be read. The path is the list of nested tags leading to the
+                        required one, such as <literal>"/a/b/c/d"</literal>, or equivalently
+                        <literal>"//b/c/d"</literal>. It is case-sensitive.
+                    </para>
                 </listitem>
             </varlistentry>
             <varlistentry>
                 <term>attributes</term>
                 <listitem>
-                    <para>a matrix of strings, the attributes names.</para>
+                    <para>
+                        vector or matrix of strings: names of attributes of the chosen tag, whose values
+                        must be read. The order of attributes does not matter wrt their actual order in
+                        the tag.
+                        <note>
+                            <itemizedlist>
+                                <listitem>
+                                    Attributes names are case-sensitive.
+                                </listitem>
+                                <listitem>
+                                    If needed, the name of a given attribute may be specified several times.
+                                </listitem>
+                            </itemizedlist>
+                        </note>
+                    </para>
+                </listitem>
+            </varlistentry>
+            <varlistentry>
+                <term>XMLsource</term>
+                <listitem>
+                    <para>
+                        points to the XML document from which informations must be extracted. It
+                        can be one of the following:
+                        <itemizedlist>
+                            <listitem>
+                                unique string: path to the XML source file (where preferences are
+                                registered). By default,
+                                <literal>SCIHOME+'/XConfiguration.xml'</literal> is considered.
+                            </listitem>
+                            <listitem>
+                                XML handle of type <literal>XMLdoc</literal>, as returned by a
+                                prior <code>xmlRead(XMLsource)</code> external instruction.
+                            </listitem>
+                        </itemizedlist>
+                    </para>
                 </listitem>
             </varlistentry>
-        </variablelist>
-        <variablelist>
             <varlistentry>
-                <term>doc</term>
+                <term>Values</term>
                 <listitem>
-                    <para>a mlist typed XMLDoc, the XML document associated to the preference file.
+                    <para>
+                        matrix of strings: Values of the chosen attributes of the chosen tag:
+                        <itemizedlist>
+                            <listitem>
+                                If the set of chosen <varname>attributes</varname> is provided as a
+                                matrix with several rows, then only the first occurrence of the chosen
+                                tag is considered, and <varname>Values(i,j)</varname> is the value of
+                                its <varname>attributes(i,j)</varname>.
+                            </listitem>
+                            <listitem>
+                                Otherwise, if the names of <varname>attributes</varname> are
+                                provided in a row vector, then
+                                <emphasis role="italic">all occurences</emphasis> of the chosen tag
+                                are considered: Results are returned with one row per occurrence,
+                                and one colum per attribute. Thus, <varname>Values(i,j)</varname>
+                                is the value of the <varname>attributes(j)</varname> for the
+                                <literal>
+                                    i<superscript>th</superscript>
+                                </literal>
+                                occurrence of the
+                                tag in the document.
+                            </listitem>
+                        </itemizedlist>
+                        If some final values are expected to be numeric rather than literal (text),
+                        <code>evstr()</code> may be applied to them to get expected numbers.
                     </para>
                 </listitem>
             </varlistentry>
     <refsection>
         <title>Description</title>
         <para>
-            Get the values of the attributes in preferences file (<literal>SCIHOME+'/XConfiguration.xml'</literal>).
+            When an XML handle returned by <code>xmlRead(..)</code> is provided as
+            <varname>XMLsource</varname>, <function>getPreferencesValue()</function> uses it
+            directly to parse the XML Preferences document opened by this prior
+            <code>xmlRead(..)</code>. This is useful when the same document must be parsed with
+            multiple calls to <function>getPreferencesValue()</function>, typically to address
+            different XML tags. In this case, one should not forget to close the XML document after
+            its whole processing.
         </para>
         <para>
-            When doc is specified, the values are searched in this document. It is useful when several requests need to be done to avoid to parse again and again the same configuration file.
+            When the path of the XML Preferences file is provided as <varname>XMLsource</varname>,
+            <function>getPreferencesValue()</function> opens the file, builds its DOM tree, parses
+            the tree for the chosen tag and attributes, and finally deletes the tree and closes the
+            file before returning results. This is what occurs with the default Xconfiguration.xml
+            file when no explicit <varname>XMLsource</varname> is specified.
         </para>
         <para>
-            All valid XPath requests are possible. For example to write the XPath request to get proxy settings:
+            The <varname>path2tag</varname> argument must be a valid "XPath" according to the
+            <ulink url="https://www.w3.org/TR/1999/REC-xpath-19991116/">W3C recommandations</ulink>.
+            Examples are given herebelow. If the path uses a intermediate or a final tag that does
+            not exist, or if one of the queried attributes does not exist, an error is yielded.
         </para>
-        <simplelist type="inline">
-            <member>
-                <para>
-                    Open the file <literal>SCIHOME+'/XConfiguration.xml'</literal> and gets the nodes names to access to the expected node:
-                </para>
-                <programlisting role="xml"><![CDATA[
-<?xml version="1.0" encoding="utf-8" standalone="no"?>
-<interface height="600" path="1/" version="0.17" width="800">
-    <general title="_(General)">
-    ...
-    </general>
-    <web title="_(Web)">
-        <body>
-            <web command-browser="" command-mailer="" default-browser="true" default-mailer="true"/>
-            <proxy enabled="false" host="" password="" port="" user=""/>
-            <previous-proxy enabled="false" host="" password="" port="" user=""/>
-        </body>
-    </web>
-    ...
-</interface>
-             ]]></programlisting>
-                <para>
-                    The path will be <literal>"/interface/web/body/proxy"</literal> (or to simplify <literal>"//web/body/proxy"</literal>).
-                </para>
-            </member>
-        </simplelist>
     </refsection>
     <refsection>
         <title>Examples</title>
-        <programlisting role="example"><![CDATA[
-getPreferencesValue("//web/body/proxy", ["enabled", "host", "port"]);
- ]]></programlisting>
+        <emphasis role="bold">Example 1:</emphasis>
+        <para>
+            Your web and proxy settings for Scilab are stored in the default
+            <literal>SCIHOME+'/XConfiguration.xml'</literal> preferences file. Let's consider the
+            following excerpt of the file:
+            <programlisting role="xml"><![CDATA[
+    <?xml version="1.0" encoding="utf-8" standalone="no"?>
+    <interface height="600" path="1/" version="0.17" width="800">
+        <general title="_(General)">
+        ...
+        </general>
+        <web title="_(Web)">
+            <body>
+                <web command-browser="" command-mailer="" default-browser="true" default-mailer="true"/>
+                <proxy enabled="false" host="" password="" port="" user=""/>
+                <previous-proxy enabled="false" host="" password="" port="" user=""/>
+            </body>
+        </web>
+        ...
+    </interface>
+              ]]></programlisting>
+        </para>
+        <para>
+            To get some informations about the proxy parameters (proxy tag), the required code
+            will be:
+            <programlisting role="scilab"><![CDATA[
+            proxy = getPreferencesValue("//web/body/proxy", ["enabled", "host", "port"]);
+     ]]></programlisting>
+        </para>
+        <para>
+            <emphasis role="bold">Example 2:</emphasis>
+        </para>
+        <para>
+            <function>getPreferencesValue()</function> can also be used to get values of a tag
+            having multiple occurrences in the <literal>XMLsource</literal> file. For instance,
+            your preferences for the Scilab's editor Scinotes are stored in the
+            <literal>SCIHOME\scinotesConfiguration.xml</literal> file. The list of most recent files
+            opened in Scinotes is stored in the following part and path:
+            <programlisting role="xml"><![CDATA[
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<Setting version="0.42">
+    <!-- SCINOTES configuration -->
+    <Profile name="scinotes">
+        <!-- .../... -->
+        <!-- Recent Opened Files Section  -->
+        <recentFiles>
+            <document path="C:\Path\to\my\first\working\dir\ged_move_entity.sci"/>
+            <document path="C:\Path\to\my\first\working\dir\ged_loop.sci"/>
+            <document path="C:\Path\to\my\first\working\dir\test_legend_move.sce"/>
+            <document path="C:\Path\to\another\working\dir2\clf.sci"/>
+        </recentFiles>
+        <!-- .../... -->
+    </Profile>
+</Setting>
+              ]]></programlisting>
+        </para>
+        <para>
+            Then, the following code will extract, return and display the column of recent files:
+            <programlisting role="example"><![CDATA[
+            scinotesFile = SCIHOME + "/scinotesConfiguration.xml";
+            recent = getPreferencesValue("//Setting/Profile/recentFiles/document", "path", scinotesFile);
+            mprintf("%s\n", recent)
+     ]]></programlisting>
+            <screen><![CDATA[
+C:\Path\to\my\first\working\dir\ged_move_entity.sci
+C:\Path\to\my\first\working\dir\ged_loop.sci
+C:\Path\to\my\first\working\dir\test_legend_move.sce
+C:\Path\to\another\working\dir2\clf.sci
+]]></screen>
+        </para>
     </refsection>
     <refsection role="see also">
         <title>See also</title>
@@ -100,6 +220,50 @@ getPreferencesValue("//web/body/proxy", ["enabled", "host", "port"]);
             <member>
                 <link linkend="setPreferencesValue">setPreferencesValue</link>
             </member>
+            <member>
+                <link linkend="xmlXPath">xmlXPath</link>
+            </member>
+            <member>
+                <ulink url="https://www.w3.org/TR/1999/REC-xpath-19991116/">XML path language</ulink>
+            </member>
+            <member>
+                <link linkend="xmlRead">xmlRead</link>
+            </member>
+            <member>
+                <link linkend="xmlDelete">xmlDelete</link>
+            </member>
+            <member>
+                <link linkend="atomsGetConfig">atomsGetConfig</link>
+            </member>
+            <member>
+                <link linkend="printsetupbox">printsetupbox</link>
+            </member>
+            <member>
+                <link linkend="csvDefault">csvDefault</link>
+            </member>
         </simplelist>
     </refsection>
+    <refsection role="history">
+        <title>History</title>
+        <revhistory>
+            <revision>
+                <revnumber>5.5.0</revnumber>
+                <revdescription>getPreferencesValue() introduced.
+                </revdescription>
+            </revision>
+            <revision>
+                <revnumber>6.0.0</revnumber>
+                <revdescription>
+                    <itemizedlist>
+                        <listitem>
+                            XMLsource can now be the path + filename of the preferences file.
+                        </listitem>
+                        <listitem>
+                            A tag with multiple occurrences can now be read.
+                        </listitem>
+                    </itemizedlist>
+                </revdescription>
+            </revision>
+        </revhistory>
+    </refsection>
 </refentry>
index cbd1b82..77c6b07 100644 (file)
@@ -1,5 +1,6 @@
 // Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
 // Copyright (C) 2014 - Scilab Enterprises - Calixte DENIZET
+// Copyright (C) 2017 - Samuel GOUGEON
 //
 // Copyright (C) 2012 - 2016 - Scilab Enterprises
 //
 // For more information, see the COPYING file which you should have received
 // along with this program.
 
-// Get preferences values
-// - xpath is something like "//web/body/proxy", the target must be a single node
-// - attributes is a matrix of strings containing the attributes names
-// - doc (optional): the prefs xml document where to get the values
-//
 function values = getPreferencesValue(xpath, attributes, doc)
     rhs = argn(2);
 
     if (rhs ~= 2 & rhs ~= 3) then
-        error(msprintf(gettext("%s: Wrong number of input arguments: %d or %d expected.\n"), "getPreferencesValue", 2, 3));
+        msg = _("%s: Wrong number of input arguments: %d or %d expected.\n")
+        error(msprintf(msg, "getPreferencesValue", 2, 3));
     end
 
     if type(xpath) <> 10 then
-        error(msprintf(gettext("%s: Wrong type for input argument #%d: String expected.\n"), "getPreferencesValue", 1));
+        msg = _("%s: Wrong type for input argument #%d: String expected.\n")
+        error(msprintf(msg, "getPreferencesValue", 1));
     end
 
     if type(attributes) <> 10 then
-        error(msprintf(gettext("%s: Wrong type for input argument #%d: Matrix of strings expected.\n"), "getPreferencesValue", 2));
+        msg = _("%s: Wrong type for input argument #%d: Matrix of strings expected.\n")
+        error(msprintf(msg, "getPreferencesValue", 2));
     end
 
     if rhs == 2 then
-        try
-            doc = xmlRead(SCIHOME + "/XConfiguration.xml");
-        catch
-            error(msprintf(gettext("%s: Invalid XConfiguration.xml file.\n"), "getPreferencesValue"));
+        doc = SCIHOME + "/XConfiguration.xml"
+    end
+    doc0 = doc
+    delDoc = (rhs == 2 | type(doc0)==10)
+    if type(doc)==10 then
+        if isfile(doc)
+            try
+                doc = xmlRead(doc0);
+            catch
+                msg = _("%s: Invalid ""%s"" file.\n")
+                error(msprintf(msg, "getPreferencesValue", tokens(doc0,["/" "\"])($)));
+            end
+        else
+            msg = _("%s: The file ""%s"" does not exist.\n")
+            error(msprintf(msg, "getPreferencesValue", doc));
         end
     elseif typeof(doc) ~= "XMLDoc" then
-        error(msprintf(gettext("%s: Wrong type for input argument #%d: A XMLDoc expected.\n"), "getPreferencesValue", 3));
+        msg = _("%s: Wrong type for input argument #%d: A XMLDoc expected.\n")
+        error(msprintf(msg, "getPreferencesValue", 3));
     end
 
     try
         xp = xmlXPath(doc, xpath);
     catch
-        if rhs == 2 then
-            xmlDelete(doc);
-        end
-        error(msprintf(gettext("%s: Invalid XPath request.\n"), "getPreferencesValue"));
-    end
-
-    if xp.size ~= 1 then
-        if rhs == 2 then
+        if delDoc then
             xmlDelete(doc);
         end
-        error(msprintf(gettext("%s: Invalid XPath request."), "getPreferencesValue"));
+        msg = gettext("%s: Invalid XPath request.\n")
+        error(msprintf(msg, "getPreferencesValue"));
     end
 
-    node = xp(1);
-    if node.type ~= "XML_ELEMENT_NODE" then
-        if rhs == 2 then
+    if xp.size == 0 then
+        if delDoc then
             xmlDelete(doc);
         end
-        error(msprintf(gettext("%s: Target node is not a XML_ELEMENT_NODE."), "getPreferencesValue"));
+        msg = gettext("%s: Invalid XPath request.")
+        error(msprintf(msg, "getPreferencesValue"));
     end
 
-    attr = node.attributes;
     values = [];
-    for a = attributes(:)'
-        v = attr(a);
-        if v ~= [] then
-            values = [values v];
-        else
-            if rhs == 2 then
+    for i = 1 : xp.size
+        node = xp(i);
+        if node.type ~= "XML_ELEMENT_NODE" then
+            if delDoc then
                 xmlDelete(doc);
             end
-            error(msprintf(gettext("%s: Invalid attribute name: %s."), "getPreferencesValue", a));
+            msg = gettext("%s: Target node is not a XML_ELEMENT_NODE.")
+            error(msprintf(msg, "getPreferencesValue"));
+        end
+    
+        attr = node.attributes;
+        for j = 1:size(attributes,"*")
+            a = attributes(j)
+            v = attr(a);
+            if v ~= [] then
+                values(i,j) = v;
+            else
+                if delDoc then
+                    xmlDelete(doc);
+                end
+                msg = gettext("%s: Invalid attribute name: %s.")
+                error(msprintf(msg, "getPreferencesValue", a));
+            end
         end
     end
-
-    if rhs == 2 then
+    if xp.size==1 then
+        values = matrix(values, size(attributes));
+    end
+    if delDoc then
         xmlDelete(doc);
     end
-    values = matrix(values, size(attributes));
 endfunction