Need suggestions for transforming a logic string

Here should go questions about transforming XML with XSLT and FOP.
tsh138
Posts: 17
Joined: Tue Feb 05, 2008 11:14 pm

Need suggestions for transforming a logic string

Post by tsh138 »

I have a logic string which is somewhat different than I am accustomed to and I am trying to transform it into an XML representation. I am thinking I will need to perform multiple passes in order to get the correct results, but I want to make sure I am not overlooking a simpler method. Any suggestions? Thanks in advance.

| = OR
& = AND
! = NOT

Example 1: 661.1049.|.1099.&.
This equates to "(661 OR 1049) AND 1099"
The XML output to represent this would look like:

Code: Select all


<criteria operator="AND">
<def ref="1099"/>
<criteria operator="OR">
<def ref="661"/>
<def ref="1049"/>
</criteria>
</criteria>
Example 2: 204.1126.1127.53.|.|.&.
This equates to (204 OR 1126 OR 1127) AND 53
The XML output to represent this would look like:

Code: Select all


<criteria operator="AND">
<def ref="53"/>
<criteria operator="OR">
<def ref="204"/>
<def ref="1126"/>
<def ref="1127"/>
</criteria>
</criteria>
Example 3: 624.1296.661.1049.|.|.|.!.
This equates to NOT(624 OR 1296 OR 661 OR 1049)
The XML output to represent this would look like:

Code: Select all


<criteria operator="OR" negate="true">
<def ref="624"/>
<def ref="1296"/>
<def ref="661"/>
<def ref="1049"/>
</criteria>
sorin_ristache
Posts: 4141
Joined: Fri Mar 28, 2003 2:12 pm

Re: Need suggestions for transforming a logic string

Post by sorin_ristache »

Hello,

Maybe it can be solved with an XSLT 2.0 stylesheet that parses an input text string and generates an output XML document as in your examples. A possible strategy is simulating a stack to which the numbers can be pushed when they are encountered in the input string and popped and included in the output XML document when an operator is encountered.


Regards,
Sorin
tsh138
Posts: 17
Joined: Tue Feb 05, 2008 11:14 pm

Re: Need suggestions for transforming a logic string

Post by tsh138 »

I think I solved it. Here it is...let me know if you see any room for improvement?

Code: Select all


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

<xsl:template match="/">
<xsl:element name="CONDITIONS">
<xsl:for-each select="node()/CONDITION">
<xsl:apply-templates select="current()"/>
</xsl:for-each>
</xsl:element>
</xsl:template>

<xsl:template match="CONDITION">
<xsl:copy-of select="current()"/>
<xsl:variable name="elementIDs">
<xsl:choose>
<xsl:when test="count(tokenize(current(), '\.')) = 2">
<xsl:value-of select="current()"></xsl:value-of>
</xsl:when>
<xsl:when test="count(tokenize(current(), '\.')) > 2">
<xsl:for-each select="reverse(tokenize(current(), '\.'))">
<xsl:if test="not(current()='|' or current()='&' or current()='!' or current()='')">
<xsl:value-of select="concat(current(), '.')"/>
</xsl:if>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:text>can't to do anything this is an obvious error in the content</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="operators">
<xsl:for-each select="reverse(tokenize(current(), '\.'))">
<xsl:if test="current()='|' or current()='&' or current()='!'">
<xsl:choose>
<xsl:when test="current()='|'">
<xsl:text>OR.</xsl:text>
</xsl:when>
<xsl:when test="current()='&'">
<xsl:text>AND.</xsl:text>
</xsl:when>
<xsl:when test="current()='!'">
<xsl:text>NOT.</xsl:text>
</xsl:when>
</xsl:choose>
</xsl:if>
</xsl:for-each>
</xsl:variable>

<xsl:choose>
<xsl:when test="(count(tokenize($elementIDs,'\.'))=0) or (count(tokenize($operators,'\.'))=0)"/><!--no need to do anything-->
<xsl:otherwise>
<xsl:copy-of select="foo:BUILDLOGIC('NONE', $elementIDs, $operators)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>

<xsl:template match="*" mode="#all">
<xsl:if test="exists(current())">
<xsl:copy-of select="current()"/>
</xsl:if>
</xsl:template>

<xsl:function name="foo:BUILDLOGIC">
<xsl:param name="prevOp"/>
<xsl:param name="ids"/>
<xsl:param name="ops"/>

<xsl:choose>
<xsl:when test="count(tokenize($ids,'\.'))=0"/><!--no need to do anything-->
<xsl:when test="count(tokenize($ops,'\.'))=0"><!-- one id left so just create the element -->
<xsl:element name="def">
<xsl:attribute name="ref"><xsl:value-of select="tokenize($ids, '\.')[1]"/></xsl:attribute>
</xsl:element>
</xsl:when>
<xsl:when test="tokenize($ops, '\.')[1] = $prevOp">
<xsl:element name="def">
<xsl:attribute name="ref"><xsl:value-of select="tokenize($ids, '\.')[1]"/></xsl:attribute>
</xsl:element>
<xsl:copy-of select="foo:BUILDLOGIC(tokenize($ops, '\.')[1], substring-after($ids, concat(tokenize($ids, '\.')[1], '.')), substring-after($ops, concat(tokenize($ops, '\.')[1], '.')))"/>
</xsl:when>
<xsl:otherwise>
<xsl:element name="criteria">
<xsl:choose>
<xsl:when test="tokenize($ops, '\.')[1]='NOT'">
<xsl:attribute name="operator"><xsl:value-of select="tokenize($ops, '\.')[2]"/></xsl:attribute>
<xsl:attribute name="negate">true</xsl:attribute>
<xsl:element name="def">
<xsl:attribute name="ref"><xsl:value-of select="tokenize($ids, '\.')[1]"/></xsl:attribute>
</xsl:element>
<xsl:copy-of select="foo:BUILDLOGIC(tokenize($ops, '\.')[2], substring-after($ids, concat(tokenize($ids, '\.')[1], '.')), substring-after($ops, concat(tokenize($ops, '\.')[2], '.')))"/>
</xsl:when>
<xsl:otherwise>
<xsl:attribute name="operator"><xsl:value-of select="tokenize($ops, '\.')[1]"/></xsl:attribute>
<xsl:element name="def">
<xsl:attribute name="ref"><xsl:value-of select="tokenize($ids, '\.')[1]"/></xsl:attribute>
</xsl:element>
<xsl:copy-of select="foo:BUILDLOGIC(tokenize($ops, '\.')[1], substring-after($ids, concat(tokenize($ids, '\.')[1], '.')), substring-after($ops, concat(tokenize($ops, '\.')[1], '.')))"/>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
</xsl:stylesheet>
Post Reply