0

I have an xml of the following structure:

MeasurementDataExport Comments ApiCall username lotId processToolId

This is a minimal example:

<MeasurementDataExport xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://my.company.de/Measurement/MeasurementDataExport.xsd">
  <Name>MyTestName</Name>
  <Comments>&lt;ApiCall&gt;&lt;username&gt;AName&lt;/username&gt;&lt;lotId&gt;12345&lt;/lotId&gt;&lt;processToolId&gt;67890&lt;/processToolId&gt;&lt;/ApiCall&gt;</Comments>

I am working on a xlst to get the value username. Here is how I get the value of comments:

<xsl:variable name="comments">
  <xsl:copy-of select="mde:MeasurementDataExport/mde:Comments"/>
</xsl:variable>

This is how the output of that variable looks:

<ApiCall><username>Test</username><lotId>12345</lotId><processToolId>67890</processToolId></ApiCall>

As you see the variable is in an xml-format and the &lt and &gt characters were already changed to > and <. But while debugging he stores that value as type "text". So I can't dig deeper like

<xsl:value-of select="$comments/ApiCall/username" />

That is the main problem: My schema only works until the node comments, everything deeper needs to be parsed. So how can I parse the value of "Comments" to a node-structure, so that I can use deeper value-of-calls?

I tried to work with node-set, but had no success so far.

6
  • Do not use xls:copy-ofin your varibale. Use <xsl:variable name="comments" select="mde:MeasurementDataExport/mde:Comments" /> Commented Apr 19, 2016 at 12:40
  • Okay. But that does not solve my problem. My variable still is a nodeset with a single node containing all the text from above. Commented Apr 19, 2016 at 12:50
  • No now it it is a result tree fragmen and your <xsl:value-of select="$comments/ApiCall/username" /> should do (if there are no default namspaces involved). But to say any more we need a (not)/working example of xml and xslt. Commented Apr 19, 2016 at 13:03
  • No, it does not. :( It just stays blank. Problem might be that my xsd schema only know comments and not the subnodes. But it is a result tree fragment, yes. Only it is not a tree, its just one node containg all text from above. So the xml was not splitted Commented Apr 19, 2016 at 13:07
  • @selmaohneh Please post a reproducible example, including a (minimal) example of the XML input - see minimal reproducible example. Commented Apr 19, 2016 at 13:12

2 Answers 2

1

There are several issues here - the first being that your XML does not have the structure you claim. The actual structure of the snippet shown is:

MeasurementDataExport
• Name (contains a text node)
• Comments (contains a text node)

The escaped markup within the string-value of Comments is not XML and cannot be parsed using XPath. This has nothing to do with the variable - you wouldn't have any more success if you tried operating on the original nodes directly.

The second issue has been pointed out in the comment by @hr_117: if you want your variable to contain a node-set (in XSLT 1.0), use select instead of xsl:copy. However, it will not make a difference in this case, because the contents will still not be XML.

In order to extract a value (such as username) from the escaped markup, you would have to either use string functions - which is not very robust - or (preferably) process the source in two passes, where the first pass would unescape the Comments and save the result to an interim file. Then you'll be able to parse the interim result as XML.

Sign up to request clarification or add additional context in comments.

2 Comments

Why is the text value no XML? The format seems right, or not?
@selmaohneh Because &lt;ApiCall&gt; is not the same thing as <ApiCall>. One is a meaningless string, the other is an XML tag.
0

The <xsl:variable> does not contain a node-set (in XSLT 1.0). It does contain a RTF(Result tree fragment). RTFs have the restriction that you can't use XPath expressions on them, therefore your line

<xsl:value-of select="$comments/ApiCall/username" />

does, at best, return a string, but not a complete node-set. The solution would be using an XSLT 2.0 processor. Because in XSLT 2.0 this restriction has been removed, see here in section "Death To the Result Tree Fragment!"

In XSLT 1.0 the result tree fragment (RTF) type is like a node-set, but it is really a second-class citizen. An RTF is what you get whenever you use xsl:variable to construct a temporary tree. The problem is that you can't then use an XPath expression to access the innards of this tree, unless you use a vendor-specific extension function, usually called something like node-set(), to convert the RTF into a first-class node-set (consisting of one root node). The rationale for the RTF data type was that it would reduce implementation burden, but since almost all existing XSLT processors provide their own version of a node-set() extension function anyway, that consideration has become moot.

The way it is now, you have to extract the username from the text() node under the <Comments> tag treating the ;lt; as text and not as < like michael.hor257k wrote in the other comment.

<xsl:template match="/">
  <xsl:variable name="userName" select="substring-before(substring-after(mde:MeasurementDataExport/mde:Comments/text(),'&lt;username&gt;'),'&lt;/username&gt;')" />
  <xsl:value-of select="$userName"/>
</xsl:template>

3 Comments

Is there no way to get the username in xslt 1.0? I am kinda forced to use 1.0.
There is. I added a way to retrieve the 'username' from the sample given.
Works great. Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.