3

I have ran into an issue with another engineer. Being a new engineer, I have to figure out the solution to this, but I haven't been able to. Any help would be appreciated, the closest thing I've found is Chunk string with XSLT but is still not quite there. I'm only able to use XSL v1.0.

A parameter is passed to my stylesheet as a giant string. It originally came from an XML Document. The string looks something like this.

With <xsl:value-of select="$servers"/> where $servers is the param for the string passed to me. The string looks like this:

<license><active_servers><server><name>MIKE</name><capacity>18</capacity><status>0</status><expiration></expiration><left>0</left><comment></comment></server><server><name>Susie</name><capacity>0</capacity><status>1</status><expiration>2014-07-04T00:00:00Z</expiration><left>5238568</left><comment></comment></server><server><name>Zoe</name><capacity>5000</capacity><status>1</status><expiration></expiration><left>0</left><comment></comment></server></active_servers></license>

This is a section of the xml data passed as a param to the stylesheet. The actual document is 300 or so lines of data. The only distinctive thing that separates these "nodes" are the <server> and </server>. Is there a way to pull data out of this if it's a really big string?

Say, for example. I need to find "Zoe" and see if she has a "expiration", if she doesn't, I need her "status". So Zoe will display "1" for status since she doesn't have expiration. While MIKE will display "0" and Susie will display 2014-07-04T00:00:00Z.

I have looked all over google and stack overflow for finding a solution to parsing/reading a giant string. But I haven't come to a solution close enough where I can make it work. As of right now, I'm stuck having no working copy, and 2 days into research without getting anywhere.

Community
  • 1
  • 1
misterbear
  • 803
  • 2
  • 13
  • 33
  • A string is not XMl and cannot be parsed as XML. Is there no way you could pass a *path* to an actual XML document as the parameter? – michael.hor257k May 20 '14 at 18:53
  • I emailed the other engineer 4 days ago who is across the world, but haven't heard back. So I take it, this is the way he wants it. I thought maybe I missed something that would be able to read a string like that. I know I can test for a string for a certain key word, like MIKE or Zoe, but I don't think I can test for the data after the keyword, am I correct? – misterbear May 20 '14 at 18:59
  • You can parse the string *as string*, using the string functions provided by XSLT 1.0 - which would be quite tedious and error-prone. You should really strive to process the input *as XML* - which means either (1) accessing the original data in an XML file; or (2) doing two transformations in series, with the first transformation saving the parameter to a file with a known path, and the second transformation reading from that file. – michael.hor257k May 20 '14 at 19:13
  • Your first solution as sending param as a XML Document with original data being the solution I had in mind. I'll talk to the engineer some more to see if I can change his mind. Thanks for your help and reassurance that I was on the right track! Could you post an answer with that and I'll mark it as answered and closed. – misterbear May 20 '14 at 19:27

2 Answers2

3

A string is not XML and cannot be parsed as XML. You could of course parse the string as string, using the string functions provided by XSLT 1.0 - which would be quite tedious and error-prone.

If possible, pass a path to an actual XML document as the parameter. Alternatively, call two transformations in series, with the first transformation saving the parameter to a file with a known path, and the second transformation reading from that file.

See also:
https://stackoverflow.com/a/14512924/3016153

Community
  • 1
  • 1
michael.hor257k
  • 113,275
  • 6
  • 33
  • 51
3

It's not possible to parse a string as XML, as @michael.hor257k correctly observed in the accepted answer, but there is a way to treat your string as a node-set by loading it as an embedded document. That is possible using the data URI scheme with the document() function. XSLT 1.0 Specification warns, however, that this is implementation dependent (the processor is not required to support any uri scheme). I tested this with XSLT 1.0 processors such as Xalan and Saxon 6 and it worked.

The solution is to append your string to the data URI scheme data:text/xml separated by a comma. You can then pass this string to your document() function and it will parse it as an XML file:

document(concat('data:text/xml,',$servers))

You can then apply any templates to the node-set.

Here is a stylesheet with a $servers parameter which should receive your string containing XML data. It will parse the string, transform the nodes in templates, and generate a XML output with some data:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output indent="yes"/>
    <xsl:param name="servers"/>

    <xsl:template match="/">
        <xsl:apply-templates select="document(concat('data:text/xml,',$servers))/license"/>
    </xsl:template>
    
    <xsl:template match="license">
        <results>
            <xsl:apply-templates/>
        </results>
    </xsl:template>
    
    <!-- server without expiration - get status -->
    <xsl:template match="server[not(string(expiration))]">
        <server name="{name}" status="{status}" />
    </xsl:template>
    
    <!-- server with expiration - get expiration -->
    <xsl:template match="server">
        <server name="{name}" expiration="{expiration}" />
    </xsl:template>
    
</xsl:stylesheet>

If you run this with any source, and your data passed as a parameter you get:

<results>
   <server name="MIKE" status="0"/>
   <server name="Susie" expiration="2014-07-04T00:00:00Z"/>
   <server name="Zoe" status="1"/>
</results>

UPDATE: this feature also depends on parser support for data-uris. I wasn't aware of that since my XML environment has that support, so changing different XSLT processors didn't make any difference. I used Oxygen XML Editor 15.2, in a Mac OS X environment. I will update this information when I discover exactly which parser it is using.

Community
  • 1
  • 1
helderdarocha
  • 23,209
  • 4
  • 50
  • 65
  • This is an interesting idea, however I cannot reproduce your success on any processor. I get a "Malformed URL" warning using both Saxon and Xalan. Could you correct the example here: http://xsltransform.net/bFukv8r – michael.hor257k May 22 '14 at 11:10
  • @michael.hor257k It seems that it depends on data-uri support by the parser as well. It works in Oxygen XML Editor 15.2 (and command line environment, which shares the same configuration), but I wasn't able to get it to work with a standard Java 8 TraX implementation yet. – helderdarocha May 22 '14 at 15:31