Jump to content
abartsch

How to address cdata blocks

Recommended Posts

Hi everybody, I'm new to XSLT and face a problem with cdata which is most probably a simple question for you. I have following XML input (which is mandatory):

<table title="Installed Packages" separator="=" caption="true" appendix="false">		    <![CDATA[Variant Name = APS]]>		    <![CDATA[b04hlr02a_VD = Z04Y5V641200]]>		    ...</table>

I'd like to address each cdata line separately but I don't know how. The corresponding XSLT part looks like that:

<xsl:when test="table[@title='Installed Packages']">	   <tr id="trResultOK">		    <td style="text-align:center"><xsl:value-of select="id"/></td>		    <td style="text-align:center"><xsl:value-of select="result"/></td>		    <td style="text-align:center"><xsl:value-of select="priority"/></td>		    <td><xsl:value-of select="text[@type='description']"/></td>		    <td><xsl:value-of select="table"/></td>	   </tr></xsl:when>

As you can see, for now I address the table element just as a whole but I'd like to have each cdata block separately i.e. every cdata should be one line in the HTML document ending with a newline. Or with other words the table data should have separate lines for each single cdata block. The HTML could look like following:

<td>	   Variant Name = APS<br />	   b04hlr02a_VD = Z04Y5V641200<br />	  ...</td>

I'd be very thankful for any help.

Share this post


Link to post
Share on other sites

Are you using an XSLT 1.0 processor or an XSLT 2.0 processor?This is not possible with XSLT 1.0 for sure... I'm not entirely positive about XSLT 2.0.

Share this post


Link to post
Share on other sites

In case one cannot address cdata separately using XPATH neither with XSLT 1.0 nor with 2.0 maybe you have an idea to modify the cdata within a template. I already tried XSL function like substring-before and substring-after but this does not work for me. PS: Within Perl I would implement a pattern match for "string = string" but how to do this using XSL?

Share this post


Link to post
Share on other sites

Sorry, but XSLT is not the right tool to deal with CDATA sections as the XSLT/XPath/XQuery data model does not know any CDATA sections so the stylesheet operates on a tree model with a single text node where the original markup in the source document has adjacent text and/or CDATA sections.If you need to manipulate CDATA section then you need a different data model and API, like DOM or like LINQ to XML.

Share this post


Link to post
Share on other sites

I'm calling the XSLT processor using PHP. Maybe, I have some possibilities to manipulate cdata in within PHP call? Here comes the code snipet:

$xml = new DOMDocument;$xml->load("xml/$hostname.log.xml");$xsl = new DOMDocument;$xsl->load("xml/results.xsl");$proc = new XSLTProcessor;$proc->importStyleSheet($xsl);print(trim($proc->transformToXML($xml)));

Thanks so far!

Share this post


Link to post
Share on other sites

PHP's DOM implementation has http://www.php.net/manual/en/class.domcdatasection.php so with the DOM you should be able to find and distinguish CDATA section nodes. So pseudo code (sorry, I don't code with PHP) would be e.g.

  $table = $xml->getElementsByTagName("table")->item(0);  for ($i = $table->childNodes->length - 1; i >= 0; i--) {    $child = $table->childNodes->item(i);    if ($child->nodeType == [b]XML_CDATA_SECTION_NODE) {[/b]	  $cdataWrapper = $xml->createElement("wrapper");	  $cdataWrapper->textContent = $child->nodeValue;	  $child->parentNode->replaceChild($cdataWrapper, $child);   }  }

Then in your stylesheet code you could match on e.g. table/wrapper.

Share this post


Link to post
Share on other sites

Based on Martin's idea I could solve my problem:

	$xml = new DOMDocument;	$xml->formatOutput = true;	$xml->load("xml/$hostname.log.xml");	$elements = $xml->getElementsByTagName("*");	foreach($elements as $element)	{	 foreach($element->childNodes as $item)	 {	  if( $item->nodeType == 4 ) // XML_CDATA_SECTION_NODE	  {	   $cdataWrapper = $xml->createElement("wrapper", $item->nodeValue);	   $element->parentNode->appendChild($cdataWrapper);	   // $item->parentNode->replaceChild($cdataWrapper, $item);	  }	 }	}	$xsl = new DOMDocument;	$xsl->load("xml/wrapper.xsl");	$proc = new XSLTProcessor;	$proc->importStyleSheet($xsl);	print(trim($proc->transformToXML($xml)));

Unfortunately, the replaceChild method did not work for me but I guess it's because I need the for-loop starting with the last cdata block as proposed by Martin. Anyway, this code adds XML wrapper tags for each cdata block separately which I can address via XSLT:

		  <xsl:when test="wrapper">		   <td><xsl:for-each select="wrapper">		    <xsl:value-of select="." /><br />		   </xsl:for-each></td>		  </xsl:when>

Thanks to all who were supporting me! :good:

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...