Jump to content

How to address cdata blocks


abartsch

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.

Link to comment
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.

Link to comment
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?

Link to comment
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.

Link to comment
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!

Link to comment
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.

Link to comment
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:

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...