<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="no" indent="yes" />
<xsl:strip-space elements="*" />
<!-- <xsl:template match="//edx:rule" xmlns:edx="http://www.cisco.com/BRL">
<xsl:apply-templates />
</xsl:template> -->
<xsl:template match="*">
<xsl:element name="{local-name(.)}">
<xsl:apply-templates select="#* | node()" />
</xsl:element>
</xsl:template>
<xsl:template match="lhs" name="lhsTemplate">
<xsl:element name="lhs">
<xsl:choose>
<xsl:when test="incident != ''">
<xsl:for-each select="incident">
<xsl:element name="freeForm">
<xsl:element name="text">
<xsl:apply-templates select="." />
<!-- <xsl:call-template name = "incidentTemplate"/> -->
</xsl:element>
</xsl:element>
</xsl:for-each>
</xsl:when>
<xsl:when test="evaluate != ''">
<xsl:for-each select="evaluate">
<xsl:element name="freeForm">
<xsl:element name="text">
<xsl:apply-templates select="." />
<!-- <xsl:call-template name = "evaluateTemplate"/> -->
</xsl:element>
</xsl:element>
</xsl:for-each>
</xsl:when>
<xsl:when test="ruleReference != ''">
<xsl:value-of select="ruleReference" />
</xsl:when>
<xsl:otherwise>
<xsl:text> no elements encountered in lhs block</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:template>
<xsl:template match="rhs" name="rhsTemplate">
<xsl:element name="rhs">
<xsl:choose>
<xsl:when test="modify != ''">
<xsl:for-each select="modify">
<xsl:element name="freeForm">
<xsl:element name="text">
<xsl:apply-templates select="." />
</xsl:element>
</xsl:element>
</xsl:for-each>
</xsl:when>
<xsl:when test="tryCatchBlock/try/callFunction != ''">
<xsl:for-each select="tryCatchBlock/try/callFunction">
<xsl:element name="freeForm">
<xsl:element name="text">
<xsl:apply-templates select="." />
<xsl:text>;</xsl:text>
</xsl:element>
</xsl:element>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<xsl:text> no elements encountered in Try block</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:template>
<!-- FIELE VALUES TEMPLATE -->
<xsl:template match="fieldValues" name="fieldValuesTemplate">
<xsl:for-each select="fieldValue" >
<!-- <xsl:if test="field!=''">
<xsl:value-of select="field"/>
<xsl:text>=</xsl:text>
</xsl:if> -->
<xsl:choose>
<xsl:when test="value/literal !=''">
<xsl:value-of select="value/literal"/>
</xsl:when>
<xsl:when test="value/formula !=''">
<xsl:apply-templates select="value/formula"/>
</xsl:when>
<xsl:when test="value/callMethodOnBoundVariable != ''">
<xsl:apply-templates select="value/callMethodOnBoundVariable"/>
</xsl:when>
<xsl:when test="value/callApi !=''">
<xsl:apply-templates select="."/>
</xsl:when>
<xsl:when test="value/boundVariable !=''">
<xsl:value-of select="value/boundVariable"/>
</xsl:when>
<xsl:when test="value/enum != ''">
<xsl:value-of select="value/enum"/>
</xsl:when>
<xsl:when test="value/content != ''">
<xsl:value-of select="value/content"/>
</xsl:when>
<xsl:otherwise>
<xsl:text>No values encountered inside field</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:if test="position() != last()">
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:template>
<!-- INSERT LOGICAL TEMPLATE -->
<xsl:template match="insertLogical" name="insertLogicalTemplate">
<xsl:value-of select="factType"/>
<xsl:text> </xsl:text>
<xsl:value-of select="boundName"/>
<xsl:text> = new </xsl:text>
<xsl:value-of select="factType"/>
<xsl:text>(</xsl:text>
<xsl:if test="fieldValues!=''">
<xsl:apply-templates select="fieldValues"/>
</xsl:if>
<xsl:text>);</xsl:text>
<xsl:text>insertLogical</xsl:text>
<xsl:text>(</xsl:text>
<xsl:value-of select="boundName"/>
<xsl:text>);</xsl:text>
</xsl:template>
<!-- END OF THE INSERT LOGICAL TEMPLATE -->
<!-- ASSERT MODIFY TEMPLATE -->
<xsl:template match="modify" name="modifyTemplate">
<xsl:text>modify</xsl:text>
<xsl:text>( </xsl:text>
<xsl:value-of select="variable"/>
<xsl:text> ){ </xsl:text>
<xsl:if test="fieldValues!=''">
<xsl:apply-templates select="fieldValues"/>
</xsl:if>
<xsl:text> };</xsl:text>
</xsl:template>
<!-- END OF THE MODIFY TEMPLATE -->
<!-- RETRACT TEMPLATE -->
<xsl:template match="retract" name="retractTemplate">
<xsl:text>retract(</xsl:text>
<xsl:value-of select="."/>
<xsl:text>);</xsl:text>
</xsl:template>
<!-- END OF THE RETRACT TEMPLATE -->
<!-- start leftOperandTemplate -->
<xsl:template match="leftOperand" name="leftOperandTemplate">
<xsl:choose>
<xsl:when test="field/fieldName != ''">
<xsl:value-of select="field/fieldName" />
</xsl:when>
<xsl:when test="boundVariable/variableName != ''">
<xsl:value-of select="boundVariable/variableName" />
</xsl:when>
<xsl:when test="expression != ''">
<xsl:apply-templates select="expression" /> <!-- TO DO -->
</xsl:when>
<xsl:when test="literal != ''">
<xsl:value-of select="literal" />
</xsl:when>
<xsl:when test="value/content != ''">
<xsl:value-of select="value/content" />
</xsl:when>
<xsl:when test="callFunction != ''">
<xsl:apply-templates select="callFunction" />
</xsl:when>
<xsl:when test="formula != ''">
<xsl:apply-templates select="formula" />
</xsl:when>
<xsl:when test="callApi != ''">
<xsl:apply-templates select="callApi" />
</xsl:when>
<xsl:when test="callMethodOnBoundVariable != ''">
<xsl:apply-templates select="callMethodOnBoundVariable" />
</xsl:when>
<xsl:otherwise>
<xsl:text>No left operands found!</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- end leftOperandTemplate -->
<!-- start Right operand template -->
<xsl:template match="rightOperand" name="rightOperandTemplate">
<xsl:choose>
<xsl:when test="boundVariable/variableName != ''">
<xsl:value-of select="boundVariable/variableName" />
</xsl:when>
<xsl:when test="configurableVariable/variableName != ''">
<xsl:value-of select="configurableVariable/variableName" />
</xsl:when>
<xsl:when test="literal != ''">
<xsl:value-of select="literal" />
</xsl:when>
<xsl:when test="value/content != ''">
<xsl:value-of select="value/content" />
</xsl:when>
<xsl:when test="callFunction != ''">
<xsl:apply-templates select="callFunction" />
</xsl:when>
<xsl:when test="formula != ''">
<xsl:apply-templates select="formula" />
</xsl:when>
<xsl:when test="callApi != ''">
<xsl:apply-templates select="callApi" />
</xsl:when>
<xsl:when test="callMethodOnBoundVariable != ''">
<xsl:apply-templates select="callMethodOnBoundVariable" />
</xsl:when>
<xsl:when test="expression != ''">
<xsl:apply-templates select="expression" /> <!-- TO DO -->
</xsl:when>
<xsl:otherwise>
<xsl:text>No right operands found!</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- end Right operand template -->
<!-- start Comparison operator template -->
<xsl:template match=" operator | comparisonOperator" name="compareOperatorTemplate">
<xsl:choose>
<xsl:when test=".='gt'">
<xsl:value-of select="' > '"
disable-output-escaping="yes" />
</xsl:when>
<xsl:when test=". = 'lt'">
<xsl:value-of select="' < '"
disable-output-escaping="yes" />
</xsl:when>
<xsl:when test=".='eq'">
<xsl:value-of select="' == '" disable-output-escaping="yes" />
</xsl:when>
<xsl:when test=". = 'ne'">
<xsl:value-of select="' != '" disable-output-escaping="yes" />
</xsl:when>
<xsl:when test=". = 'lt or eq'">
<xsl:value-of select="' <= '"
disable-output-escaping="yes" />
</xsl:when>
<xsl:when test=". = 'gt or eq'">
<xsl:value-of select="' >= '"
disable-output-escaping="yes" />
</xsl:when>
<xsl:when test=". = 'matches'">
<xsl:value-of select="' matches '" />
</xsl:when>
<xsl:when test=". = 'not matches'">
<xsl:value-of select="' not matches '" />
</xsl:when>
<xsl:when test=". = 'contains'">
<xsl:value-of select="' contains '" />
</xsl:when>
<xsl:when test=". = 'not contains'">
<xsl:value-of select="' not contains '" />
</xsl:when>
<xsl:when test=". = 'memberOf'">
<xsl:value-of select="' memberOf '" />
</xsl:when>
<xsl:when test=". = 'not memberOf'">
<xsl:value-of select="' not memberOf '" />
</xsl:when>
<xsl:when test=". = 'sounds like'">
<xsl:value-of select="' sounds like '" />
</xsl:when>
<xsl:otherwise>
<xsl:text>No operator found</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- End Comparison operator template -->
<xsl:template match="evaluate" name="evaluateTemplate">
<xsl:text disable-output-escaping="yes">eval(</xsl:text>
<xsl:if test=". !=''">
<xsl:apply-templates select="leftOperand" />
<xsl:if test="comparisonOperator !=''">
<xsl:apply-templates select="comparisonOperator" />
</xsl:if>
<xsl:apply-templates select="rightOperand" />
</xsl:if>
<xsl:text>)</xsl:text>
</xsl:template>
<!-- END EVALUATE TEMPLATE -->
<!-- start CALL FUNCTION TEMPLATE -->
<xsl:template match="callFunction" name="callFunctionTemplate">
<xsl:if test=". !=''">
<xsl:if test="returnType!='' and returnTypeBoundName !='' ">
<xsl:value-of select="returnType" />
<xsl:text> </xsl:text>
<xsl:value-of select="returnTypeBoundName" />
<xsl:text>=</xsl:text>
</xsl:if>
<xsl:if test="functionName!=''">
<xsl:value-of select="functionName" />
<xsl:text>(</xsl:text>
<!-- <xsl:apply-templates select="args"/> -->
<xsl:call-template name="argsTemplate" />
</xsl:if>
<xsl:text>)</xsl:text>
</xsl:if>
</xsl:template>
<!-- END OF THE CALL FUNCTION TEMPLATE -->
<!-- START ARGS TEMPLATE -->
<xsl:template match="args" name="argsTemplate">
<xsl:if test="args/arg != ''">
<xsl:for-each select="args/arg">
<xsl:choose>
<xsl:when test="callMethodOnBoundVariable != ''">
<xsl:apply-templates select="callMethodOnBoundVariable" />
</xsl:when>
<xsl:when test="callApi != ''">
<xsl:apply-templates select="callApi" />
</xsl:when>
<xsl:when test="value != ''">
<xsl:value-of select="value/content" />
</xsl:when>
<xsl:when test="literal != ''">
<xsl:value-of select="." />
</xsl:when>
<xsl:when test="boundVariable != ''">
<xsl:value-of select="boundVariable/variableName" />
</xsl:when>
<xsl:otherwise>
<xsl:text>No Args</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:if test="position() != last()">
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:if>
</xsl:template>
<!-- END OF THE ARGS TEMPLATE -->
<!-- START of the Call Method on Bound Variable function -->
<xsl:template match="callMethodOnBoundVariable" name="callMethodOnBoundVariableTemplate">
<xsl:value-of select="boundVariableName" />
<xsl:text>.</xsl:text>
<xsl:value-of select="methodName" />
<xsl:text>(</xsl:text>
<!-- <xsl:value-of select="params/param/boundVariable" /> -->
<xsl:call-template name="paramsTemplate" />
<xsl:text>)</xsl:text>
</xsl:template>
<!-- End of the Call Method on Bound Variable function -->
<!-- START CALL API TEMPLATE -->
<xsl:template match="callApi" name="callApiTemplate">
<!-- <xsl:if test="returnType != 'void'"> <xsl:value-of select="returnType
" /> <xsl:text> </xsl:text> </xsl:if> -->
<xsl:value-of select="boundVaribleName" />
<xsl:if test="boundVaribleName[.!='']">
<xsl:text>=</xsl:text>
</xsl:if>
<xsl:value-of select="serviceVariableName" />
<xsl:text>.</xsl:text>
<xsl:value-of select="methodName" />
<xsl:text>(</xsl:text>
<xsl:call-template name="paramsTemplate" />
<xsl:text>)</xsl:text>
</xsl:template>
<!-- END call API TEMPLATE -->
<!-- FORMULA TEMPLATE -->
<xsl:template match="formula" name="formulaTemplate">
<xsl:if test="'leftOperand'">
<xsl:call-template name="formulaWithoutPeranthesisTemplate" />
</xsl:if>
<xsl:if test="'peranthesis'">
<xsl:call-template name="formulaWithPeranthesisTemplate" />
</xsl:if>
</xsl:template>
<!-- END OF THE FORMULA TEMPLATE -->
<!-- start Formula without peranthesis template -->
<xsl:template match="formulaWithoutPeranthesis" name="formulaWithoutPeranthesisTemplate">
<xsl:if test="leftOperand">
<xsl:apply-templates select="leftOperand" />
</xsl:if>
<xsl:if test="arithmeticOperator">
<xsl:apply-templates select="arithmeticOperator" />
</xsl:if>
<xsl:if test="rightOperand">
<xsl:apply-templates select="rightOperand" />
</xsl:if>
</xsl:template>
<!-- End Formula without peranthesis template -->
<!-- start Formula withparenthesis template -->
<xsl:template match="formulaWithPeranthesis" name="formulaWithPeranthesisTemplate">
<xsl:if test="peranthesis != ''">
<xsl:text>(</xsl:text>
<xsl:if test="peranthesis/leftOperand !=''">
<xsl:apply-templates select="peranthesis/leftOperand" />
</xsl:if>
<xsl:if test="peranthesis/arithmeticOperator">
<xsl:apply-templates select="peranthesis/arithmeticOperator" />
</xsl:if>
<xsl:if test="peranthesis/rightOperand">
<xsl:apply-templates select="peranthesis/rightOperand" />
</xsl:if>
<xsl:text>)</xsl:text>
</xsl:if>
</xsl:template>
<!-- END Formula with parenthesis template -->
<!-- START ARITHMETIC OPERATOR -->
<xsl:template match="arithmeticOperator" name="arithmeticOperatorTemplate">
<xsl:choose>
<xsl:when test="'+'">
<xsl:value-of select=" . " />
</xsl:when>
<xsl:when test="'-'">
<xsl:value-of select=" . " />
</xsl:when>
<xsl:when test="'*'">
<xsl:value-of select=" . " />
</xsl:when>
<xsl:when test="'/'">
<xsl:value-of select=" . " />
</xsl:when>
<xsl:when test="'%'">
<xsl:value-of select=" . " />
</xsl:when>
<xsl:otherwise>
<xsl:text>Not a valid airthmetic operator</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- END ARITHMETIC OPERATOR -->
<!-- START OF THE PARAMS TEMPLATE -->
<xsl:template match="params" name="paramsTemplate">
<xsl:if test="params/param != ''">
<xsl:for-each select="params/param">
<xsl:choose>
<xsl:when test="callMethodOnBoundVariable != ''">
<xsl:apply-templates select="callMethodOnBoundVariable" />
</xsl:when>
<xsl:when test="formula != ''">
<xsl:apply-templates select="formula" />
</xsl:when>
<xsl:when test="callApi != ''">
<xsl:apply-templates select="callApi" />
</xsl:when>
<xsl:when test="value != ''">
<xsl:value-of select="value/content" />
</xsl:when>
<xsl:when test="literal != ''">
<xsl:text>"</xsl:text>
<xsl:value-of select="." />
<xsl:text>"</xsl:text>
</xsl:when>
<xsl:when test="boundVariable != ''">
<xsl:value-of select="boundVariable" />
</xsl:when>
<xsl:when test="enum != ''">
<xsl:value-of select="enum" />
</xsl:when>
<xsl:otherwise>
<xsl:text>No Param</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:if test="position() != last()">
<xsl:text>,</xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:if>
</xsl:template>
<!-- END OF THE PARAMS TEMPLATE -->
<!--START COMPOSITE PATTERN TEMPLATE -->
<xsl:template match='compositePattern' name="compositePatternTemplate">
<xsl:if test="type != ''">
<xsl:value-of select="type" />
<xsl:text> </xsl:text>
</xsl:if>
<xsl:apply-templates select="patterns" />
</xsl:template>
<!-- END COMPOSITE PATTERN TEMPLATE -->
<xsl:template name="tagAndContentRemovalTemplate"
match=" nuggetVersion |nuggetId | ruleVersion | notes|ruleId | nuggetName | application | brlVersion | modelVersion | notes|declaration|preprocess " />
<xsl:template name="tagRemovalTemplate"
match=" ruleSection | blocks | block |actions | fieldRestriction | declaration | preprocess | tryCatchBlock |constraintList ">
<xsl:apply-templates />
<!-- set field and expression TBD -->
</xsl:template>
</xsl:stylesheet>
The Input file looks like below.
<?xml version="1.0" encoding="UTF-8"?>
<rule >
<name>IC-86</name>
<ruleId>1001</ruleId>
<ruleVersion>1.0</ruleVersion>
<nuggetId>1122</nuggetId>
<brlVersion>1.0</brlVersion>
<modelVersion>1.0</modelVersion>
<attributes>
<attribute>
<attributeName>agenda-group</attributeName>
<value>commonATSP</value>
</attribute>
</attributes>
<notes>Some text description about the rule, like what exactly it does...</notes>
<declaration />
<preprocess />
<ruleSection>
<blocks>
<block order="0">
<lhs>
<evaluate>
<leftOperand>
<boundVariable>
<variableName>$count</variableName>
<classType>Integer</classType>
<genericType>Number</genericType>
</boundVariable>
</leftOperand>
<comparisonOperator>gt</comparisonOperator>
<rightOperand>
<literal>10</literal>
</rightOperand>
</evaluate>
</lhs>
<rhs>
<modify>
<fieldValues>
<fieldValue>
<field>name</field>
<value>
<literal>$imageVersion</literal>
</value>
<nature>1</nature>
<type>String</type>
</fieldValue>
<fieldValue>
<field>value</field>
<value>
<callMethodOnBoundVariable>
<params>
<param>
<value>
<content>0</content>
<classType>int</classType>
<genericType>Numeric</genericType>
</value>
</param>
</params>
<boundVariableName>$attributes</boundVariableName>
<methodName>get</methodName>
<returnType>String</returnType>
</callMethodOnBoundVariable>
</value>
<nature>4</nature>
<type>String</type>
</fieldValue>
<fieldValue>
<field>type</field>
<value>
<literal>imageName</literal>
</value>
<nature>1</nature>
<type>String</type>
</fieldValue>
</fieldValues>
<variable>$attribute</variable>
</modify>
</rhs>
</block>
</blocks>
</ruleSection>
</rule>
I am facing an issue with my default namespace. I have a file with the root tag as below:
<rule xmlns="http://www.max.com/BRL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.max.com/BRL ../BRLV4.xsd ">
If I remove the namespaced <rule> as seen in the above input XML, then the translation works. Otherwise, it doesn't work. That is, if I try the translation without the default namespace then I am getting the required output as below. But I need the same output when I get the XML file with the default namespace on the root tag.
<?xml version="1.0" encoding="UTF-8"?>
<rule>
<name>IC-86</name>
<attributes>
<attribute>
<attributeName>agenda-group</attributeName>
<value>commonATSP</value>
</attribute>
</attributes>
<lhs>
<freeForm>
<text>eval($count > 10)</text>
</freeForm>
</lhs>
<rhs>
<freeForm>
<text>modify( $attribute ){ $imageVersion,$attributes.get(0),imageName };</text>
</freeForm>
</rhs>
</rule>
The default namespace in the XML document must be declared in the XSLT. For example, use the prefix 'brl'.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:brl="http://www.max.com/BRL">
Then use the brl prefix when referring to the tag names. For example,
<xsl:template match="brl:lhs" name="lhsTemplate">
...
<xsl:when test="brl:incident != ''">
<xsl:for-each select="brl:incident">
If the XML document may or may not have a namespace, see my article "Stay on the XPath: Tip 5: Handling XPath select expressions that fail to match documents with a default namespace" on IBM developerWorks.
Basically, you need your stylesheet to work whether all the elements are in no namespace, or in the BRL namespace. This is an odd requirement, and the ideal solution would be to tell your upstream data provider to be consistent about using the namespace.
But if you don't have that option, you have a few others.
1) Declare a prefix for the BRL namespace in your stylesheet, and use it to match elements in that namespace or in no namespace:
<xsl:stylesheet ... xmlns:BRL="http://www.max.com/BRL">
...
<xsl:template match="lhs | BRL:lhs">
...
2) Make all your matches and selects use local-name():
<xsl:template match="*[local-name()='lhs']">...
...
(Yuck!)
3) In XSLT 2.0, you can use the wildcard for namespaces:
<xsl:template match="*:lhs">
...
<xsl:when test="*:field/*:fieldName != ''">
But again, these three are all working around a problem in the source data. They are compensating for someone not using namespaces correctly, and thus enabling them to keep on doing the same. If the schema says the input document's elements should be in the "http://www.max.com/BRL" namespace, then you should assume that they are in that namespace (whether that's the default namespace is immaterial to you), so you should always be using a namespace prefix when matching or selecting those elements with XPath.
Related
I am doing a upper case to first character content in the xml data using the delimiters (space and hyphen) and am able to get the output correctly however this template is removing the break line tag in the table td area of xml. The output should be an xml.
eg:<text>
<table>
<tbody>
<tr>
<td>test<br />testing<br />tested</td>
</tr>
I see the code transforming as continous line without break tag in the output as below:I need to see the same br tag in xml output as in input xml however by capitalizing first letter of the word.
<text>
<table>
<tbody>
<tr>
<td>Testtestingtested</td>
</tr>
I am expecting to preserve and display the same break line tag to be in output xml even after the xslt tranformation so that the output will look correct instead of continous line
I am using the below xslt transformation:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
xmlns:n1="urn:hl7-org:v3" xmlns:n2="urn:hl7-org:sdtc">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match='n1:ClinicalDocument/n1:component/n1:structuredBody/n1:component/n1:section/n1:text/n1:table/n1:tbody/n1:tr'>
<xsl:copy>
<xsl:apply-templates select='n1:td'/>
</xsl:copy>
</xsl:template>
<xsl:template match="n1:td">
<xsl:copy>
<xsl:if test="./#ID">
<xsl:attribute name="ID" xml:space="default">
<xsl:value-of select="./#ID"/>
</xsl:attribute>
</xsl:if>
<xsl:call-template name="capitalize">
<xsl:with-param name="text" select="string(.)"/>
</xsl:call-template>
</xsl:copy>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template name="capitalize">
<xsl:param name="text" />
<xsl:param name="delimiter" select = "' '"/>
<xsl:variable name="upper-case" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>
<xsl:variable name="lower-case" select="'abcdefghijklmnopqrstuvwxyz'"/>
<xsl:variable name="word" select="substring-before(concat($text, $delimiter), $delimiter)" />
<xsl:choose>
<xsl:when test="$delimiter=' '">
<!-- tokenize word by 2nd delimiter -->
<xsl:call-template name="capitalize">
<xsl:with-param name="text" select="$word"/>
<xsl:with-param name="delimiter" select="'-'"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<!-- capitalize word -->
<xsl:value-of select="translate(substring($word, 1, 1), $lower-case, $upper-case) " />
<xsl:value-of select="translate(substring($word, 2), $upper-case, $lower-case)" />
</xsl:otherwise>
</xsl:choose>
<xsl:if test="contains($text, $delimiter)">
<xsl:value-of select="$delimiter"/>
<!-- recursive call -->
<xsl:call-template name="capitalize">
<xsl:with-param name="text" select="substring-after($text, $delimiter)" />
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Can anyone check and answer?
UPDATE: Both XSLT 1.0 and 2.0 solutions
All solutions preserve your line breaks and also work if you have inline markup of the text content.
First I make the lc and uc parameters global for more minified templates:
<xsl:param name="lc" select="'abcdefghijklmnopqrstuvwxyzàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿžšœ'"/>
<xsl:param name="uc" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞŸŽŠŒ'"/>
XSLT 1.0 or 2.0: You need to rewrite your first template to this regardless of the following XSLT solutions:
<xsl:template match="n1:td">
<xsl:copy>
<xsl:if test="./#ID">
<xsl:attribute name="ID" xml:space="default">
<xsl:value-of select="./#ID"/>
</xsl:attribute>
</xsl:if>
<xsl:apply-templates select="node()" />
</xsl:copy>
<xsl:text>
</xsl:text>
</xsl:template>
XSLT 1.0
With XSLT 1.0 you need to combine a match template with a name template.
Match template: n1:td//text()
With this match template it becomes precisely what you request, make initial letter uppercase, and make letters following space and - uppercase:
<xsl:template match="n1:td//text()" >
<xsl:param name="text" select="." />
<xsl:param name="currentTextBlock" select="ancestor::n1:td[1]" />
<xsl:param name="isFirstTextNode">
<xsl:choose>
<xsl:when test="preceding::text()[ancestor::n1:td[generate-id(.) = generate-id($currentTextBlock)]]">false</xsl:when>
<xsl:otherwise>true</xsl:otherwise>
</xsl:choose>
</xsl:param>
<xsl:choose>
<xsl:when test="$isFirstTextNode = 'true'">
<xsl:value-of select="translate(substring($text, 1, 1), $lc, $uc)" />
<xsl:call-template name="capitalize">
<xsl:with-param name="text" select="$text" />
<xsl:with-param name="remainingText" select="substring($text,2)" />
<xsl:with-param name="index" select="2" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="capitalize">
<xsl:with-param name="text" select="$text" />
<xsl:with-param name="remainingText" select="$text" />
<xsl:with-param name="index" select="1" />
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
If you also want initial letter for each text node to be uppercase without adding space or hyphen, you can use this:
<xsl:template match="n1:td//text()" >
<xsl:param name="text" select="." />
<xsl:value-of select="translate(substring($text, 1, 1), $lc, $uc)" />
<xsl:call-template name="capitalize">
<xsl:with-param name="text" select="$text" />
<xsl:with-param name="remainingText" select="substring($text,2)" />
<xsl:with-param name="index" select="2" />
</xsl:call-template>
</xsl:template>
Name template: capitalize
This name template is can be used "as is" with both of the above match templates.
<xsl:template name="capitalize">
<xsl:param name="text" select="''" />
<xsl:param name="remainingText" select="''" />
<xsl:param name="index" select="1" />
<xsl:if test="$remainingText != ''">
<xsl:variable name="currentChar" select="substring($remainingText, 1, 1)" />
<xsl:choose>
<xsl:when test="$index = 1">
<xsl:value-of select="translate($currentChar, $uc, $lc)" />
</xsl:when>
<xsl:otherwise>
<xsl:variable name="previousChar" select="substring($text, $index - 1, 1)" />
<xsl:choose>
<xsl:when test="$previousChar = ' ' or $previousChar = '-'">
<xsl:value-of select="translate($currentChar, $lc, $uc)" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="translate($currentChar, $uc, $lc)" />
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
<xsl:call-template name="capitalize">
<xsl:with-param name="text" select="$text" />
<xsl:with-param name="remainingText" select="substring($remainingText, 2)" />
<xsl:with-param name="index" select="$index + 1" />
</xsl:call-template>
</xsl:if>
</xsl:template>
XSLT 2.0 (same as before):
This solution does precisely what you request, make initial letter uppercase, and make letters following space and - uppercase:
<xsl:template match="n1:td//text()" >
<xsl:param name="text" select="." />
<xsl:param name="currentTextBlock" select="ancestor::n1:td[1]" />
<xsl:param name="isFirstTextNode">
<xsl:choose>
<xsl:when test="preceding::text()[ancestor::n1:td[generate-id(.) = generate-id($currentTextBlock)]]">false</xsl:when>
<xsl:otherwise>true</xsl:otherwise>
</xsl:choose>
</xsl:param>
<xsl:for-each select="tokenize(replace(replace($text,'(.)','$1\\n'),'\\n$',''),'\\n')">
<xsl:variable name="pos" select="position()" />
<xsl:variable name="char" select="." />
<xsl:choose>
<xsl:when test="$isFirstTextNode = 'true' and $pos = 1">
<xsl:value-of select="translate($char, $lc, $uc) " />
</xsl:when>
<xsl:when test="substring($text, $pos - 1, 1) = ' ' or substring($text, $pos - 1, 1) = '-'">
<xsl:value-of select="translate($char, $lc, $uc) " />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="translate($char, $uc, $lc)" />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
If you also want initial letter for each text node to be uppercase without adding space or hyphen, you can use this:
<xsl:template match="n1:td//text()" >
<xsl:param name="text" select="." />
<xsl:param name="currentTextBlock" select="ancestor::n1:td[1]" />
<xsl:for-each select="tokenize(replace(replace($text,'(.)','$1\\n'),'\\n$',''),'\\n')">
<xsl:variable name="pos" select="position()" />
<xsl:variable name="char" select="." />
<xsl:choose>
<xsl:when test="$pos = 1">
<xsl:value-of select="translate($char, $lc, $uc) " />
</xsl:when>
<xsl:when test="substring($text, $pos - 1, 1) = ' ' or substring($text, $pos - 1, 1) = '-'">
<xsl:value-of select="translate($char, $lc, $uc) " />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="translate($char, $uc, $lc)" />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>
The problem is your call on string(.), which takes the string value of the element: this strips out all markup.
You should be doing a recursive descent using xsl:apply-templates at each level to apply template rules to child nodes, all the way down to the leaf text nodes, and then your template rule for text nodes should be doing the case conversion.
Except that your capitalize logic seems to be trying to do something smart (I'm not sure what) which means it might need to look at something larger than a single text node. You might need a different rule for the first text node and for subsequent text nodes: it's hard to be sure without seeing a spec.
Another approach to this kind of problem is to do multiple passes: the first pass replaces the <br/> elements with some textual marker, e.g. "§br§", in the next pass you process the text as a string, and then finally you convert the markers back to element nodes.
With XSLT 3.0 you could do the first pass using fn:serialize() and the final pass using fn:parse-xml-fragment(); the "textual marker" would then be the actual lexical markup "<br/>" as a string of five characters. (But take care not to capitalise it!)
how to remove hyphen from string like "19650512-0065" to "196505120065"
using this template : passing theID =
<xsl:template name="unformatLFPartyID">
<xsl:param name="theID" select="." />
<xsl:variable name="idSuffix" select="string-length($theID) - 3" />
<xsl:choose>
<xsl:when test="contains($theID,'-')">
<xsl:value-of select="substring($theID,0,$idSuffix)" />
<xsl:value-of select="substring($theID, $idSuffix)" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$theID" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Try replacing the xsl:variable and entire xsl:choose with:
<xsl:value-of select="translate($theID,'-','')"/>
I have this xml that needs to be transformed:
<?xml version="1.0" encoding="utf-8"?>
<racine>
<index>
<Parent nom="00000002" Name="" Address="" />
<Meter numSerie="00000002" />
<arrêté dateArrêté="28/02/2015 00:00:00">
<ValeurIndex Libelle="PMAXVALUE0">0.104</ValeurIndex>
</arrêté>
</index>
<index>
<Parent nom="00000002B" Name="" Address="" />
<Meter numSerie="" />
<arrêté dateArrêté="28/02/2015 00:00:00">
<ValeurIndex Libelle="R1INDEX0">3.754</ValeurIndex>
<ValeurIndex Libelle="PMAXVALUE0">1.047</ValeurIndex>
</arrêté>
</index>
</racine>
The xslt that make the transformation is:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="ISO-8859-1"/>
<!-- Parcours des noeuds "racine/index" -->
<xsl:variable name="v_separateur">
<xsl:text>,</xsl:text>
</xsl:variable>
<!-- sort by date desc" -->
<xsl:template match="/racine">
<xsl:apply-templates select="index">
<xsl:sort select="arrêté/#dateArrêté" order="descending" data-type="number"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="index">
<!-- get repeating values once -->
<xsl:variable name="constants">
<!-- SP_ID -->
<xsl:value-of select="Parent/#nom"/>
<xsl:value-of select="$v_separateur"/>
<!-- METER_NUMBER-->
<xsl:value-of select="Meter/#numSerie"/>
<xsl:value-of select="$v_separateur"/>
<!-- DATE & TIME-->
<xsl:value-of select="arrêté/#dateArrêté"/>
<xsl:value-of select="$v_separateur"/>
</xsl:variable>
<!-- Only Process OBIS* values ignore other -->
<xsl:apply-templates select="arrêté/ValeurIndex[
#Libelle='EA.R00'
or #Libelle='EA.R01'
or #Libelle='EA.R02'
or #Libelle='EA.R03'
or #Libelle='EA.R05'
or #Libelle='EA.R06'
or #Libelle='EA.R07'
or #Libelle='EAE.R00'
or #Libelle='AEINDEX0'
or #Libelle='AEINDEX1'
or #Libelle='AEINDEX2'
or #Libelle='AEINDEX3'
or #Libelle='AEINDEX5'
or #Libelle='AEINDEX6'
or #Libelle='AEINDEX7'
or #Libelle='R1INDEX0'
or #Libelle='PMAXVALUE0'
]">
<xsl:with-param name="constants" select="$constants"/>
</xsl:apply-templates>
<!-- ADD NEW ROW -->
<xsl:value-of select="$constants"/>
<xsl:text>KWH</xsl:text>
<xsl:value-of select="$v_separateur"/>
<xsl:value-of select="$v_separateur"/>
<xsl:choose>
<xsl:when test="arrêté/ValeurIndex[#Libelle='EA.R00'] > arrêté/ValeurIndex[#Libelle='EA.R02']">
<xsl:value-of select="arrêté/ValeurIndex[#Libelle='EA.R00']"/>
<xsl:text>
</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="arrêté/ValeurIndex[#Libelle='EA.R02']"/>
<xsl:text>
</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="ValeurIndex"> <!--match="ValeurIndex"-->
<xsl:param name="constants"/>
<xsl:value-of select="$constants"/>
<xsl:choose>
<xsl:when test="#Libelle = 'EA.R00'">KWH,PUNTA</xsl:when>
<xsl:when test="#Libelle = 'EA.R01'">KWH,VALLE</xsl:when>
<xsl:when test="#Libelle = 'EA.R02'">KWH,LLANO</xsl:when>
<xsl:when test="#Libelle = 'EA.R03'">KW,</xsl:when>
<xsl:when test="#Libelle = 'EA.R05'">KWH,</xsl:when>
<xsl:when test="#Libelle = 'EA.R06'">KVH,ER_Q2</xsl:when>
<xsl:when test="#Libelle = 'EA.R07'">KVH,ER_Q3</xsl:when>
<xsl:when test="#Libelle = 'EAE.R00'">KVH,ER_Q4</xsl:when>
<xsl:when test="#Libelle = 'AEINDEX0'">KWH,PUNTA_SA</xsl:when>
<xsl:when test="#Libelle = 'AEINDEX1'">KWH,VALLE_SA</xsl:when>
<xsl:when test="#Libelle = 'AEINDEX2'">KWH,LLANO_SA</xsl:when>
<xsl:when test="#Libelle = 'AEINDEX3'">KWH,</xsl:when>
<xsl:when test="#Libelle = 'AEINDEX5'">KWH,ENERSAL</xsl:when>
<xsl:when test="#Libelle = 'AEINDEX6'">KW,PUNTA</xsl:when>
<xsl:when test="#Libelle = 'AEINDEX7'">KW,VALLE</xsl:when>
<xsl:when test="#Libelle = 'R1INDEX0'">KW,LLANO</xsl:when>
<xsl:when test="#Libelle = 'PMAXVALUE0'">KW, PUNTA_SA</xsl:when>
<xsl:otherwise>
<xsl:value-of select="Param[#code = 'TYPE_EQP']/#value"/>
</xsl:otherwise>
</xsl:choose>
<xsl:value-of select="$v_separateur"/>
<xsl:value-of select="."/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
I want to have just the lines that we have some value, so in this case:
00000002,00000002,28/02/2015 00:00:00,KW, PUNTA_SA,0.104
00000002B,,28/02/2015 00:00:00,KW,LLANO,3.754
00000002B,,28/02/2015 00:00:00,KW, PUNTA_SA,1.047
But as we put the maximum of EA.R00 and EA.R02 I will have a row without date and without data. I want that in case that both values dont exist dont write anything. As the xslt is right now, I will obtain:
00000002,00000002,28/02/2015 00:00:00,KW, PUNTA_SA,0.104
00000002,00000002,28/02/2015 00:00:00,KWH,,
00000002B,,28/02/2015 00:00:00,KW,LLANO,3.754
00000002B,,28/02/2015 00:00:00,KW, PUNTA_SA,1.047
00000002B,,28/02/2015 00:00:00,KWH,,
(I dont want to see the 2nd and 5th row)
Thanks
The extra lines your refer to are output by the code after the comment <!-- ADD NEW ROW -->. What you can do is wrap this code in an xsl:if to check if either EA.R00 or EA.R02 exists.
Try this:
<!-- ADD NEW ROW -->
<xsl:if test="arrêté/ValeurIndex[#Libelle='EA.R00' or #Libelle='EA.R02']">
<xsl:value-of select="$constants"/>
<xsl:text>KWH</xsl:text>
<xsl:value-of select="$v_separateur"/>
<xsl:value-of select="$v_separateur"/>
<xsl:choose>
<xsl:when test="arrêté/ValeurIndex[#Libelle='EA.R00'] > arrêté/ValeurIndex[#Libelle='EA.R02']">
<xsl:value-of select="arrêté/ValeurIndex[#Libelle='EA.R00']"/>
<xsl:text>
</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="arrêté/ValeurIndex[#Libelle='EA.R02']"/>
<xsl:text>
</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
Hi i'm having the below xml.
<primaryie>
<content-style font-style="bold">Administration</content-style>
</primaryie>
and when i'm applying the below xslt it is working fine.(the content-style part)
<xsl:template match="primaryie">
<div class="primaryie">
<xsl:apply-templates select="content-style"/>
<xsl:if test="contains(current()/text(), '.')">
<xsl:variable name="numberString" select="substring(current()/text(), string-length(substring-before(current()/text(),'.'))-1)"></xsl:variable>
<xsl:call-template name="numbersToLink">
<xsl:with-param name="numbersString" select="$numberString"></xsl:with-param>
</xsl:call-template>
</xsl:if>
</div>
</xsl:template>
<xsl:template name="numbersToLink">
<xsl:param name="numbersString"></xsl:param>
<xsl:choose>
<xsl:when test="contains($numbersString, ',')">
<xsl:call-template name="splitByComma">
<xsl:with-param name="numString" select="$numbersString"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($numbersString, '-')">
<xsl:call-template name="splitByHyphen">
<xsl:with-param name="numString" select="$numbersString"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="5 >= string-length(normalize-space($numbersString))">
<xsl:variable name="x">
<xsl:value-of select="substring-after($numbersString,'.')"></xsl:value-of>
</xsl:variable>
<xsl:variable name="y">
<xsl:value-of select="normalize-space(substring-before($numbersString,'.'))"></xsl:value-of>
</xsl:variable>
<xsl:variable name="conca">
<xsl:value-of select="concat('er:#BVI_CH_0',$y,'/P',$y,'-',$x)"/>
</xsl:variable>
<a href="{$conca}">
<xsl:value-of select="$numbersString"/>
</a>
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="splitByComma">
<xsl:param name="numString"></xsl:param>
<xsl:choose>
<xsl:when test="contains(substring-before($numString,','), '-')">
<xsl:call-template name="splitByHyphen">
<xsl:with-param name="numString" select="$numString"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="contains($numString,',')">
<xsl:variable name="abc">
<xsl:value-of select="normalize-space(substring-before($numString,'.'))"/>
</xsl:variable>
<xsl:variable name="def">
<xsl:value-of select="substring-before(substring-after($numString,'.'),',') "/>
</xsl:variable>
<xsl:variable name="conct">
<xsl:value-of select="concat('er:#BVI_CH_0',$abc,'/P',$abc,'-',$def)"/>
<!--"concat(concat('er:#BVI_CH_0',,'/P',$y,'-',$x)"/-->
</xsl:variable>
<a href="{$conct}">
<xsl:value-of select="substring-before($numString,',')"/>
</a>
<xsl:text>, </xsl:text>
<xsl:if test="contains(substring-after($numString,','), '.')">
<xsl:call-template name="numbersToLink">
<xsl:with-param name="numbersString" select="normalize-space(substring-after($numString,','))"/>
</xsl:call-template>
</xsl:if>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template name="splitByHyphen">
<xsl:param name="numString"></xsl:param>
<xsl:choose>
<xsl:when test="contains($numString,'-')">
<xsl:variable name="abc">
<xsl:value-of select="normalize-space(substring-before($numString,'.'))"/>
</xsl:variable>
<xsl:variable name="def">
<xsl:value-of select="substring-before(substring-after($numString,'.'),'-') "/>
</xsl:variable>
<xsl:variable name="conct">
<xsl:value-of select="concat('er:#BVI_CH_0',$abc,'/P',$abc,'-',$def)"/>
<!--"concat(concat('er:#BVI_CH_0',,'/P',$y,'-',$x)"/-->
</xsl:variable>
<a href="{$conct}">
<!--<xsl:value-of select="substring-before($numString,'-')"/>-->
<xsl:value-of select="substring-before($numString,'-')"/>
</a>
<xsl:text>–</xsl:text>
<xsl:if test="contains(substring-after($numString,'-'), '.')">
<xsl:call-template name="numbersToLink">
<xsl:with-param name="numbersString" select="normalize-space(substring-after($numString,'-'))"/>
</xsl:call-template>
</xsl:if>
</xsl:when>
</xsl:choose>
</xsl:template>
but i have a special case in the same document as below xml states.
<primaryie>
<content-style font-style="bold">VIRRGIN system</content-style> 7.204, 7.205
</primaryie>
here when i'm applying the above template it is working with content-style, but i want it to work also with numberstolink template.
the outputs are as below.
current:
<div class="primaryie"><span class="font-style-bold">Virgin Islands Special Trust Act (VISTA) 9.077</span></div>
expexted:
<div class="primaryie"><span class="font-style-bold">Virgin Islands Special Trust Act (VISTA) 9.077</span></div>
Please change this below portion in your code
<xsl:template match="primaryie">
<div class="primaryie">
<xsl:apply-templates select="content-style"/>
<xsl:if test="contains(current(), '.')">
<xsl:variable name="numberString" select="substring(current(), string-length(substring-before(current(),'.'))-1)"></xsl:variable>
<xsl:call-template name="numbersToLink">
<xsl:with-param name="numbersString" select="$numberString"></xsl:with-param>
</xsl:call-template>
</xsl:if>
</div>
</xsl:template>
Use only Current() instead of Current()/Text()
Output for give XML is
<div class="primaryie">VIRRGIN system 7.204, 7.205</div>
I'm transforming my XSLT-stylesheets into documentation, and I want a rich experience within the comment nodes for each code-chunk, therefore I want to convert the following comment and output as xhtml:
String:
# This is a title with __bold__ text and *italic* #
This is just a normal line
- list point with some __bold__
- list point with a "link"[http://www.stackoverflow.com]
Wanted output:
<h1> This is a title with <strong>bold</strong> and <span>italic</span> </h1>
<p>This is a normal line</p>
<ul>
<li>list point with some <strong>bold</strong></li>
<li>list point with a link</li>
</ul>
I tried with a recursive function that uses xsl:analyze-string recursively from a ruleset, but can't find a solution that works really well.
Anyone have done this lately, or is there some frameworks out there that has functions to do this ?
thanx in advance! :)
Edit: Added one dirty example:
<!-- Output comments -->
<xsl:template match="comment()" mode="COMMENT">
<xsl:copy-of select="ips:groupReplace(normalize-space(.),
'
(.*)(\n|\r)(.*),
(.*)\*(.*)\*(.*),
(.*)\*\*(.*)\*\*(.*),
(.*)__(.*)__(.*),
(.*)#(.*)#(.*),
(.*)-(.*)
',
'
br,
span.italic,
span.bold,
strong,
h1,
li
')" />
</xsl:template>
<!-- Initializing the iterateRegex function -->
<xsl:function name="ips:groupReplace">
<xsl:param name="string" as="xs:string" />
<xsl:param name="search" />
<xsl:param name="replace" />
<xsl:variable name="regex" select="tokenize($search, ',')" />
<xsl:variable name="replacements" select="tokenize($replace, ',')" />
<xsl:copy-of select="ips:iterateRegex(count($replacements), $string, $regex, $replacements)" />
</xsl:function>
<!-- Iterate each regex -->
<xsl:function name="ips:iterateRegex">
<xsl:param name="counter" />
<xsl:param name="string" />
<xsl:param name="list_regex" />
<xsl:param name="list_replace" />
<xsl:variable name="newStr">
<xsl:analyze-string select="$string" regex="{normalize-space($list_regex[$counter])}" flags="xm">
<xsl:matching-substring>
<xsl:variable name="cc" select="contains($list_replace[$counter], '.')" />
<xsl:variable name="tag" select="normalize-space(if ($cc) then (substring-before($list_replace[$counter], '.')) else ($list_replace[$counter]))" />
<xsl:copy-of select="regex-group(1)" />
<xsl:choose>
<xsl:when test="normalize-space(regex-group(2)) = ''">
<xsl:element name="{$tag}" />
</xsl:when>
<xsl:otherwise>
<xsl:element name="{$tag}" >
<xsl:if test="$cc">
<xsl:attribute name="class" select="substring-after($list_replace[$counter],'.')" />
</xsl:if>
<xsl:copy-of select="regex-group(2)" />
</xsl:element>
</xsl:otherwise>
</xsl:choose>
<xsl:copy-of select="regex-group(3)" />
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:copy-of select="." />
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:variable>
<xsl:variable name="count" select="number($counter) - 1" />
<xsl:choose>
<xsl:when test="$count > 0">
<xsl:copy-of select="ips:iterateRegex($count, $newStr, $list_regex, $list_replace)" />
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$newStr" />
</xsl:otherwise>
</xsl:choose>
</xsl:function>
I think you would need a parser. So this stylesheet implements a verbose one:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="text" name="block">
<xsl:param name="pString" select="."/>
<xsl:if test="$pString != ''">
<xsl:choose>
<xsl:when test="starts-with($pString,'#')">
<xsl:call-template name="header">
<xsl:with-param name="pString"
select="substring($pString,2)"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="starts-with($pString,'
')">
<xsl:call-template name="list">
<xsl:with-param name="pString"
select="substring($pString,2)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="paragraph">
<xsl:with-param name="pString"
select="$pString"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
<xsl:template name="header">
<xsl:param name="pString"/>
<xsl:variable name="vInside"
select="substring-before($pString,'#
')"/>
<xsl:choose>
<xsl:when test="$vInside != ''">
<h1>
<xsl:call-template name="inline">
<xsl:with-param name="pString" select="$vInside"/>
</xsl:call-template>
</h1>
<xsl:call-template name="block">
<xsl:with-param name="pString"
select="substring-after($pString,'#
')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="paragraph">
<xsl:with-param name="pString"
select="concat('#',$pString)"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="list">
<xsl:param name="pString"/>
<xsl:variable name="vCheckList" select="starts-with($pString,'- ')"/>
<xsl:choose>
<xsl:when test="$vCheckList">
<ul>
<xsl:call-template name="listItem">
<xsl:with-param name="pString" select="$pString"/>
</xsl:call-template>
</ul>
<xsl:call-template name="block">
<xsl:with-param name="pString">
<xsl:call-template name="afterlist">
<xsl:with-param name="pString" select="$pString"/>
</xsl:call-template>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="block">
<xsl:with-param name="pString" select="$pString"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="paragraph">
<xsl:param name="pString"/>
<xsl:choose>
<xsl:when test="contains($pString,'
')">
<p>
<xsl:value-of select="substring-before($pString,'
')"/>
</p>
</xsl:when>
<xsl:otherwise>
<p>
<xsl:value-of select="$pString"/>
</p>
</xsl:otherwise>
</xsl:choose>
<xsl:call-template name="block">
<xsl:with-param name="pString"
select="substring-after($pString,'
')"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="afterlist">
<xsl:param name="pString"/>
<xsl:choose>
<xsl:when test="starts-with($pString,'- ')">
<xsl:call-template name="afterlist">
<xsl:with-param name="pString"
select="substring-after($pString,'
')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$pString"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="listItem">
<xsl:param name="pString"/>
<xsl:if test="starts-with($pString,'- ')">
<li>
<xsl:call-template name="inline">
<xsl:with-param name="pString"
select="substring-before(substring($pString,3),'
')"/>
</xsl:call-template>
</li>
<xsl:call-template name="listItem">
<xsl:with-param name="pString"
select="substring-after($pString,'
')"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template name="inline">
<xsl:param name="pString" select="."/>
<xsl:if test="$pString != ''">
<xsl:choose>
<xsl:when test="starts-with($pString,'__')">
<xsl:call-template name="strong">
<xsl:with-param name="pString"
select="substring($pString,3)"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="starts-with($pString,'*')">
<xsl:call-template name="span">
<xsl:with-param name="pString"
select="substring($pString,2)"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="starts-with($pString,'"')">
<xsl:call-template name="link">
<xsl:with-param name="pString"
select="substring($pString,2)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="substring($pString,1,1)"/>
<xsl:call-template name="inline">
<xsl:with-param name="pString"
select="substring($pString,2)"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:template>
<xsl:template name="strong">
<xsl:param name="pString"/>
<xsl:variable name="vInside" select="substring-before($pString,'__')"/>
<xsl:choose>
<xsl:when test="$vInside != ''">
<strong>
<xsl:value-of select="$vInside"/>
</strong>
<xsl:call-template name="inline">
<xsl:with-param name="pString"
select="substring-after($pString,'__')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'__'"/>
<xsl:call-template name="inline">
<xsl:with-param name="pString" select="$pString"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="span">
<xsl:param name="pString"/>
<xsl:variable name="vInside" select="substring-before($pString,'*')"/>
<xsl:choose>
<xsl:when test="$vInside != ''">
<span>
<xsl:value-of select="$vInside"/>
</span>
<xsl:call-template name="inline">
<xsl:with-param name="pString"
select="substring-after($pString,'*')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'*'"/>
<xsl:call-template name="inline">
<xsl:with-param name="pString" select="$pString"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="link">
<xsl:param name="pString"/>
<xsl:variable name="vInside"
select="substring-before($pString,'"')"/>
<xsl:choose>
<xsl:when test="$vInside != ''">
<xsl:call-template name="href">
<xsl:with-param name="pString"
select="substring-after($pString,'"')"/>
<xsl:with-param name="pInside" select="$vInside"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'"'"/>
<xsl:call-template name="inline">
<xsl:with-param name="pString" select="$pString"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="href">
<xsl:param name="pString"/>
<xsl:param name="pInside"/>
<xsl:variable name="vHref"
select="substring-before(substring($pString,2),']')"/>
<xsl:choose>
<xsl:when test="starts-with($pString,'[') and $vHref != ''">
<a href="{$vHref}">
<xsl:value-of select="$pInside"/>
</a>
<xsl:call-template name="inline">
<xsl:with-param name="pString"
select="substring-after($pString,']')"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat('"',$pInside,'"')"/>
<xsl:call-template name="inline">
<xsl:with-param name="pString" select="$pString"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
With this input:
<text>
# This is a title with __bold__ text and *italic* #
This is just a normal line
- list point with some __bold__
- list point with a "link"[http://www.stackoverflow.com]
</text>
Output:
<h1> This is a title with
<strong>bold</strong> text and
<span>italic</span>
</h1>
<p>This is just a normal line</p>
<ul>
<li>list point with some
<strong>bold</strong>
</li>
<li>list point with a
link
</li>
</ul>
Note: Look how many templates are similar (they follow a pattern), so these could be parametrized. I didn't do that in this case because there seems to be more questions which need some sort of parser, so by the end of the week I will repost an answer implementing functional parser and parser combinators pattern that make very easy to write parsers (just writing its grammar rules).
Edit: XSLT 2.0 solution. This stylesheet:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="text">
<xsl:param name="pString" select="."/>
<xsl:analyze-string select="$pString"
regex="(#(.*)#
)|((- (.*)
)+)">
<xsl:matching-substring>
<xsl:choose>
<xsl:when test="regex-group(1)">
<h1>
<xsl:call-template name="inline">
<xsl:with-param name="pString"
select="regex-group(2)"/>
</xsl:call-template>
</h1>
</xsl:when>
<xsl:when test="regex-group(3)">
<ul>
<xsl:call-template name="list">
<xsl:with-param name="pString"
select="regex-group(3)"/>
</xsl:call-template>
</ul>
</xsl:when>
</xsl:choose>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:if test=".!='
'">
<p>
<xsl:call-template name="inline">
<xsl:with-param name="pString"
select="normalize-space(.)"/>
</xsl:call-template>
</p>
</xsl:if>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
<xsl:template name="list">
<xsl:param name="pString"/>
<xsl:analyze-string select="$pString" regex="- (.*)
">
<xsl:matching-substring>
<li>
<xsl:call-template name="inline">
<xsl:with-param name="pString"
select="regex-group(1)"/>
</xsl:call-template>
</li>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:template>
<xsl:template name="inline">
<xsl:param name="pString" select="."/>
<xsl:analyze-string select="$pString"
regex="(__(.*)__)|(\*(.*)\*)|("(.*)"\[(.*)\])">
<xsl:matching-substring>
<xsl:choose>
<xsl:when test="regex-group(1)">
<strong>
<xsl:value-of select="regex-group(2)"/>
</strong>
</xsl:when>
<xsl:when test="regex-group(3)">
<span>
<xsl:value-of select="regex-group(4)"/>
</span>
</xsl:when>
<xsl:when test="regex-group(5)">
<a href="{regex-group(7)}">
<xsl:value-of select="regex-group(6)"/>
</a>
</xsl:when>
</xsl:choose>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
</xsl:stylesheet>
Output:
<h1> This is a title with
<strong>bold</strong> text and
<span>italic</span>
</h1>
<p>This is just a normal line</p>
<ul>
<li>list point with some
<strong>bold</strong>
</li>
<li>list point with a
link
</li>
</ul>
This transformation (111 lines):
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:my="my:my"
exclude-result-prefixes="xml xsl xs my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:variable name="vLines" select="tokenize(., '\n')"/>
<xsl:sequence select="my:parse-lines($vLines)"/>
</xsl:template>
<xsl:function name="my:parse-lines" as="element()*">
<xsl:param name="pLines" as="xs:string*"/>
<xsl:sequence select=
"my:parse-line($pLines, 1, count($pLines))"/>
</xsl:function>
<xsl:function name="my:parse-line" as="element()*">
<xsl:param name="pLines" as="xs:string*"/>
<xsl:param name="pLineNum" as="xs:integer"/>
<xsl:param name="pTotalLines" as="xs:integer"/>
<xsl:if test="not($pLineNum gt $pTotalLines)">
<xsl:variable name="vLine" select="$pLines[$pLineNum]"/>
<xsl:variable name="vLineLength"
select="string-length($vLine)"/>
<xsl:choose>
<xsl:when test=
"starts-with($vLine, '#')
and
ends-with($vLine, '#')
">
<xsl:variable name="vInnerString"
select="substring($vLine, 2, $vLineLength -2)"/>
<h1>
<xsl:sequence select="my:parse-string($vInnerString)"/>
</h1>
<xsl:sequence select=
"my:parse-line($pLines, $pLineNum+1, $pTotalLines)"/>
</xsl:when>
<xsl:when test=
"starts-with($vLine, '- ')
and
not(starts-with($pLines[$pLineNum -1], '- '))
">
<ul>
<li>
<xsl:sequence select="my:parse-string(substring($vLine, 2))"/>
</li>
<xsl:sequence select=
"my:parse-line($pLines, $pLineNum+1, $pTotalLines)"/>
</ul>
</xsl:when>
<xsl:when test="starts-with($vLine, '- ')">
<li>
<xsl:sequence select="my:parse-string(substring($vLine, 2))"/>
</li>
<xsl:sequence select=
"my:parse-line($pLines, $pLineNum+1, $pTotalLines)"/>
</xsl:when>
<xsl:otherwise>
<p>
<xsl:sequence select="my:parse-string($vLine)"/>
</p>
<xsl:sequence select=
"my:parse-line($pLines, $pLineNum+1, $pTotalLines)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:function>
<xsl:function name="my:parse-string" as="node()*">
<xsl:param name="pS" as="xs:string"/>
<xsl:analyze-string select="$pS" flags="x" regex=
'(__(.*?)__)
|
(\*(.*?)\*)
|
("(.*?)"\[(.*?)\])
'>
<xsl:matching-substring>
<xsl:choose>
<xsl:when test="regex-group(1)">
<strong>
<xsl:sequence select="my:parse-string(regex-group(2))"/>
</strong>
</xsl:when>
<xsl:when test="regex-group(3)">
<span>
<xsl:sequence select="my:parse-string(regex-group(4))"/>
</span>
</xsl:when>
<xsl:when test="regex-group(5)">
<a href="{regex-group(7)}">
<xsl:sequence select="regex-group(6)"/>
</a>
</xsl:when>
</xsl:choose>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:function>
</xsl:stylesheet>
when applied on this XML document (the provided text complicated with nested constructs and wrapped in an element):
<t># This is a title with __bold__ text and *italic* #
This is just a normal line
- list point with some __bold__
- list point with a __*"link"[http://www.stackoverflow.com]*__</t>
produces the wanted, correct output:
<h1> This is a title with <strong>bold</strong> text and <span>italic</span>
</h1>
<p>This is just a normal line</p>
<p/>
<ul>
<li> list point with some <strong>bold</strong>
</li>
<li> list point with a <strong>
<span>
link
</span>
</strong>
</li>
</ul>
Do note: The RegEx mechanism of XPath 2.0 and XSLT 2.0 is adequate for solving this problem.