How to read a .properties file inside a .xsl file?

14,038

Solution 1

As a proof of concept:

Input .properties file:

# You are reading the ".properties" entry.
! The exclamation mark can also mark text as comments.
website = http://example.com
language = English
key\ with\ spaces = This is the value that could be looked up with the key "key with spaces".

Stylesheet:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:f="Functions"
  version="2.0">

  <xsl:variable name="properties" select="unparsed-text('.properties')" as="xs:string"/>

  <xsl:template match="/" name="main">
    <xsl:value-of select="f:getProperty('language')"/>
  </xsl:template>

  <xsl:function name="f:getProperty" as="xs:string?">
    <xsl:param name="key" as="xs:string"/>
    <xsl:variable name="lines" as="xs:string*" select="
      for $x in 
        for $i in tokenize($properties, '\n')[matches(., '^[^!#]')] return
          tokenize($i, '=')
        return translate(normalize-space($x), '\', '')"/>
    <xsl:sequence select="$lines[index-of($lines, $key)+1]"/>
  </xsl:function>

</xsl:stylesheet>

The f:getProperty('language') will return 'English'.

See this as a proof of concept, this needs to be improved in many ways since it does not handle many of the different ways a .properties file can be authored.

I belive Alejandro or Dimitrie probably could improve this many times.

Solution 2

For an XSLT 1.0 solution, you could use an external (parsed) general entity in an XML file that will load the properties file as part of the XML content.

For example, if you had a properties file like this, named site.properties:

foo=x
site=http://testsite.com/services/testService/v1.0
bar=y

You could create a simple XML file, named properties.xml that "wraps" the content of the properties file and loads it using an external parsed general entity:

<!DOCTYPE properties [
  <!ENTITY props SYSTEM "site.properties">
]>
<properties>
 &props;
</properties>

Then, within your XSLT you can load that properties.xml using the document() function and obtain the value for a given key:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:variable name="props" select="document('properties.xml')" />
    <xsl:template match="/">
        <output>
            <example1> 
                <!--simple one-liner -->
                <xsl:value-of select="substring-before(
                                        substring-after($props, 
                                                        concat('site','=')),
                                        '&#xA;')" />
            </example1>
            <example2>
                <!--using a template to retrieve the value 
                    of the "site" property -->
                <xsl:call-template name="getProperty">
                    <xsl:with-param name="propertiesFile" select="$props"/>
                    <xsl:with-param name="key" select="'site'"/>
                </xsl:call-template>
            </example2>
            <example3>
                <!--Another example using the template to retrieve 
                    the value of the "foo" property, 
                    leveraging default param value for properties -->
                <xsl:call-template name="getProperty">
                    <!--default $propertiesFile defined in the template, 
                        so no need to specify -->
                    <xsl:with-param name="key" select="'foo'"/>
                </xsl:call-template>
            </example3>
        </output>

    </xsl:template>

    <!--Retrieve a property from a properties file by specifying the key -->
    <xsl:template name="getProperty">
        <xsl:param name="propertiesFile" select="$props"/>
        <xsl:param name="key" />
        <xsl:value-of select="substring-before(
                                 substring-after($propertiesFile, 
                                                 concat($key,'=')), 
                                 '&#xA;')" />
    </xsl:template>

</xsl:stylesheet>

When applied to any XML input the stylesheet above will produce the following output:

<?xml version="1.0" encoding="UTF-8"?>
<output>
   <example1>http://testsite.com/services/testService/v1.0</example1>
   <example2>http://testsite.com/services/testService/v1.0</example2>
   <example3>x</example3>
</output>

Note: this strategy will only work if the content of the properties file is "XML safe". If it were to contain characters, like & or < it would result in an XML parsing error when the properties.xml file is loaded.

Share:
14,038
Sameer Malhotra
Author by

Sameer Malhotra

Updated on July 24, 2022

Comments

  • Sameer Malhotra
    Sameer Malhotra almost 2 years

    I have an XSL file which uses a a static website link as shown below:

    <xsl:template match="my_match">
    
        <xsl:variable name="variable1">
            <xsl:value-of select="sel1/Label = 'Variable1'"/>
        </xsl:variable>
        <xsl:copy-of select="sites:testPath('http://testsite.com/services/testService/v1.0', $fname, $lname,
         $email , $zip, $phone, $comments, $jps, boolean($myvar), string(cust/@custID), string(@paID))"/>
    </xsl:template>
    

    My question is that how to read a properties file(key value pair) in the xsl file. so in my properties file (e.g. site.properties) I have a key called site i.e. site=testsite.com/services/testService/v1.0

    I want to use this site key in place of specifying url value in the xsl i.e. http://testsite.com/services/testService/v1.0. The reason for doing this is that this link changes depending on the various environments.

    Is this possible? Please give your suggestions or a sample code if possible...Also if this is not possible...is there any work-around?

  • Dimitre Novatchev
    Dimitre Novatchev over 13 years
    @Per-T: Actually, I don't understand this question at all. Can you, please, explain what is this all about? THere is no input and no desired output specified.
  • Admin
    Admin over 13 years
    @Dimitre: Looks like it's reading a text/plain configuration file.
  • Admin
    Admin over 13 years
    @Per T: +1 Good answer. I would take other approach like mapping all the file to an XML represenation while parsing, so you don't do it for every function call.
  • Dimitre Novatchev
    Dimitre Novatchev over 13 years
    @Alejandro: The next thing I expect is a question to process any novel and convert it to XML -- why should we tolerate such bad questions?
  • Admin
    Admin over 13 years
    @Dimitre: Ja! I'm not sure it's such a bad question. I think it's a bad design choice: why one would need to process a plain text file with XSLT? But do note that the parsing with RegExp (or just RegExp if there is no recursive balanced structure) will be the method to implement this in any other language. I didn't see answer like: "use this specif language that takes an expressed grammar in a succinct syntax and does parse a text file" unless you use some functional parser and parser combinator implementation.
  • Sameer Malhotra
    Sameer Malhotra over 13 years
    @Dimitre: I am building a mobile app and this link: "testsite.com/services/testService/v1.0" (as shown in the xsl template)is referencing to one of the website.But it's value can be changed depending on whether it's in a production, development or real time website. So in Dev environment this value could be "localhost:8080/services/testService/v1.0". If I could change this in a properties file then no need to worry about changing it anywhere else...I hope I answered it...If not shoot me another question...
  • Dimitre Novatchev
    Dimitre Novatchev over 13 years
    @Sameer: In order to have a question, you must show the specific input, the exact output wanted and to state the properties that the transformation must satisfy. I don't see the neither the input, nor the output. Please, specify them, if you really need more than purely theoretical answers
  • Dimitre Novatchev
    Dimitre Novatchev over 13 years
    @Alejandro: I don't mind processing text -- what I find ridiculous is the absence of any specified input and any specified wanted output. Can't believe people can seriously as such "questions".
  • Per T
    Per T over 13 years
    @Dimitre: I can agree that the "question" could be better specified and that I did some assumptions. I assumed Sameer wanted to parse a .properties file often used in java apps and in this case the data in the file doesn't really matter since we know the syntactics of the file. My idea was to make a general purpose solution for any .properties file, a function which would return the property value for any given property key.
  • Dimitre Novatchev
    Dimitre Novatchev over 13 years
    @Per-T: I am sure you did a good job. However, noone in the xslt tag is supposed to know what a ".properties file" is.
  • Sameer Malhotra
    Sameer Malhotra over 13 years
    @Dimitre: This is simple question. I don't know why you are making a big deal out of it. I don't have to tell you the overall architecture or anything like that. The simple question is that how to read a properties file(key value pair) in the xsl file. so in my properties file(site.properties) I have a key called "site=testsite.com/services/testService/v1.0" and I want to use this site key in place of specifying url value in the xsl. If you don't know the answer that's fine.Just don't make it more complicated for others. I appreciate you help. Thanks Per-T,I will try your solution....
  • Dimitre Novatchev
    Dimitre Novatchev over 13 years
    @Sameer: Now for the first time you have provided the necessary information to make this more like a true question. Please, edit your question and put this there. It happens that I know how to solve such problems (once they are really defined) :) In fact I have written in XSLT a parser for JSON and for XPath 2.0.
  • Sameer Malhotra
    Sameer Malhotra over 13 years
    @Per-T: Is there any possible solution for XSLT1.0 since this is the version we are using for now?..I can press my team to use xslt2.0 but it will take forever to get the approval....
  • Per T
    Per T over 13 years
    @Sameer: Not in the way I've tried to solve it now. XSLT 1.0 isn't able to parse the content of an plain text file as Dimitre explains the linked question. But as I said earlier, you could send the property value as a parameter through your parser and to the stylesheets instead. Just declare a default value in your stylesheets which can be overwritten depending on your working environment.
  • ramcrys
    ramcrys about 8 years
    @Per T: When I use the above code, an error is encountered (in Firefox): "Error during XSLT transformation: An unknown XPath extension function was called". There are some threads on this error, but after I try removing the namespace f: and xs:, it still does not work. Do you have any idea ?
  • Per T
    Per T about 8 years
    @ramcrys: That code was never intended for use in browser. No browser, to my knowledge, supports XSLT 2.0 and probably never will.