Limitations of Eric van der Vlist's RelaxNG simplicification - relaxng

All,
I am trying to simplify a RelaxNG schema using Eric van der Vlist's simplification.xsl, but I'm getting errors:
runtime error: file ./simplification.xsl line 741 element element
xsl:element: The effective name '' is not a valid QName.
runtime error: file ./simplification.xsl line 751 element element
xsl:element: The effective name '' is not a valid QName.
runtime error: file ./simplification.xsl line 759 element element
xsl:element: The effective name '' is not a valid QName.
runtime error: file ./simplification.xsl line 759 element element
xsl:element: The effective name '' is not a valid QName.
runtime error: file ./simplification.xsl line 759 element element
xsl:element: The effective name '' is not a valid QName.
It seems it has something to do with some names getting constructed dynamically:
<xsl:template match="rng:start[not(preceding-sibling::rng:start) and following-sibling::rng:start]" mode="step7.18">
<xsl:copy>
<xsl:apply-templates select="#*" mode="step7.18"/>
<xsl:element name="{parent::*/rng:start/#combine}">
<xsl:call-template name="start7.18"/>
</xsl:element>
</xsl:copy>
</xsl:template>
I haven't started getting into it any deeper, but perhaps someone already has a clue on what might be causing this.

Is there some reason not to use jing -s instead?

Apparently, I wasn't the first one to run into these issues. This web site also refers to some problems running simplification.xsl, and includes some fixes. I'm just copying it in here, for future reference.
In step 10 : prefix "rng:" was missing in lines <xsl:with-param name="node-name" select="'rng:group'"/> resulting with markups <group> with default namespace (which is not RelaxNG) in output.
In step 14 : add concatenation of prefix "rng:" before value of "combine" attributes in lines <xsl:param name="node-name" select="concat('rng:',parent::*/rng:start/#combine)"/>.
In step 14 : In template <xsl:template match="rng:start[not(preceding-sibling::rng:start) and following-sibling::rng:start]"> I removed the element addition <xsl:element name="{parent::*/rng:start/#combine}"> because it results to an extra <rng:choice> surrounding the other <rng:choice> inside the <rng:start>.
In step 15 : seems that template <xsl:template match="/*"> has a higher priority than template <xsl:template match="/rng:grammar">, so I had to add a precision : <xsl:template match="/*[not(self::rng:grammar)]">.
In step 15 : missing "rng:parentRef/#name" in erasing template : <xsl:template match="rng:define|rng:define/#name|rng:ref/#name|rng:parentRef/#name"/> in order to keep the id generated in "name" attribute of <parentRef>.
After copying in my original RelaxNG grammar in the given web site, the whole transformation completes without any problem.

Related

XSLT: variables and "empty" labels

I have an XML datafile containing among other things a string of arbitrarily many comma separated values. I want those values to be displayed in a web browser as a list with one value per line. So I wrote an XSLT template that takes this string, displays the first value followed by a linebreak tag (<br/>), properly name-spaced, and resources with the remainder of the string. In effect, the commas are being replaced by HTML <br/> tags.
Now, when I store the result of calling that template in a xsl:variable, and display that through xsl:value-of, then the HTML tags disappear: what is shown is the string minus the commas.
When I display the result directly by having the xsl:call-template in place of the xsl:value-of, all is fine, and the values appear in a list.
So, what's going on?
Is this behavior an implementation artifact, or is it standard XSLT?
Use xsl:copy-of instead of xsl:value-of if you want to output nodes (like your br elements), xsl:value-of creates a simple text node with the string value(s) selected.
Here is an example that shows the difference between xsl:value-of and xsl:copy-of, you will note that it is not the use of the variable with newly created br elements that makes the difference, it is simply the use of xsl:value-of that creates a text() node with the string conversion of the selection:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html" indent="yes" version="5" doctype-system="about:legacy-doctype"/>
<xsl:variable name="var">Phrase 1.<br/>Phrase 2.<br/>Phrase 3.</xsl:variable>
<xsl:template match="/">
<html>
<head>
<title>.NET XSLT Fiddle Example</title>
</head>
<body>
<section>
<h1>Example 1: value-of</h1>
<xsl:value-of select="$var"/>
</section>
<section>
<h1>Example 2: copy-of</h1>
<xsl:copy-of select="$var"/>
</section>
<xsl:apply-templates select="//p"/>
<xsl:apply-templates select="//p" mode="copy-of"/>
</body>
</html>
</xsl:template>
<xsl:template match="p">
<section>
<h1>Example 1: value-of</h1>
<xsl:value-of select="."/>
</section>
</xsl:template>
<xsl:template match="p" mode="copy-of">
<section>
<h1>Example 1: copy-of</h1>
<xsl:copy-of select="."/>
</section>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/gWmuiJy/1
Output is
Example 1: value-of
Phrase 1.Phrase 2.Phrase 3.
Example 2: copy-of
Phrase 1.
Phrase 2.
Phrase 3.
Example 1: value-of
Line 1.Line 2.Line 3.
Example 1: copy-of
Line 1.
Line 2.
Line 3.
It seems that you hit the boundaries of the RTF ("Result tree fragment"):
When you use an XML fragment to initialize a variable or a parameter, then the variable or parameter is of the
"result tree fragment" datatype. This is an XSLT 1.0 specific datatype [just like node-set, but slightly different].
A result tree fragment is equivalent to a node-set that contains just the root node.
You cannot apply operators like "/", "//" or predicate on a result tree fragments. They are only applicable for node-set datatypes.
[...]
a) In XSLT 1.0
The resolution of this is to convert the result tree fragment into a node-set. I am not aware of any oracle specific xpath extension functions that can do this trick for you.
You could use EXSLT to achieve this.
b) Use XSLT 2.0
You can code your transformations in XSLT 2.0. XSLT 2.0 deprecates ResultTreeFragments i.e. if you are modeling an XSLT 2.0 transformation, and you create a variable or a parameter that holds a tree fragment, it is implicitly a node sequence.
So without using an XSLT version greater than 1, you're out of luck. So better use XSLT-2.0 or 3.0 to solve this problem.
Is this behavior an implementation artifact, or is it standard XSLT?
It is standard for XSLT-1.0, but not for XSLT-2.0+.

How to put 'and' condition to remove an xml element from an xslt

I am new to XSLT and got a condition to remove an element from XML file on the basis of condition applied in XSLT. I have to remove en element on the basis of 2 conditions on the same attribute.
Here is my dummy code:
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="cdm:attributeList/cdm:attribute[cdm:attributeName = 'format'] and cdm:attributeList/cdm:attribute[cdm:attributeValue = 'XYZ']" />
while running the XSLT file I get the following error:
1. Extra illegal tokens: 'and'
2. "exclude-result-prefixes" attribute is not allowed on the xsl:output element!
Could someone please help me out in this?
Thanks.
The template matching condition is incorrect, and operator is not allowed when matching template. You need to modify the template matching condition as below which corresponds to the combination of the required conditions.
<xsl:template match="cdm:attributeList/cdm:attribute[cdm:attributeName = 'format'][cdm:attributeValue = 'XYZ']" />
For the second issue of exclude-result-prefixes, it is an attribute of <xsl:stylesheet> and not <xsl:output>. So if you do not want the output nodes to have the cdm prefix, modify the <xsl:stylesheet> as below
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:cdm="http://someurl" exclude-result-prefixes="cdm">

Concatenate to existing value in xlst

With XSLT 1.0 I simply want to add a negative sign before the value in the Identifier element. The stylesheet I have shown below returns the same (i.e. the first instance) Identifier value for each instance of RToP. There can be more than one RToP. PLease advise how to modify the match so I return the desired output below. Thanks. I'm omitting the namespace in the xml below.
<TRAN><DE><REF>
<RToP><Identifier>100</Identifier>
</RToP>
<RToP><Identifier>150</Identifier>
</RToP>
</TRAN></DE></REF>
Existing output
<TRAN><DE><REF>
<RToP><Identifier>-100</Identifier>
</RToP>
<RToP><Identifier>-100</Identifier>
</RToP>
</TRAN></DE></REF>
Desired output
<TRAN><DE><REF>
<RToP><Identifier>-100</Identifier>
</RToP>
<RToP><Identifier>-150</Identifier>
</RToP>
</TRAN></DE></REF>
Existing stylesheet
<xsl:template match="//my:TRAN/my:DE/my:REF/my:RToP/my:Identifier[position()]">
<my:Identifier>
<xsl:value-of select="concat('-', //my:TRAN/my:DE/my:REF/my:RToP/my:Identifier[position()])"/>
</my:Identifier>
</xsl:template>
For this type of transformation you need to be use relative path instead of absolute path.
first you have to create at identical transformation to retain its structure.
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
than you have to define Identifier as template that run only on Identifier and there is no need to use predicates for that.
<xsl:template match="Identifier">
<Identifier>
<xsl:value-of select="concat('-', .)"/>
</Identifier>
</xsl:template>

XSLT 1 - How can I replace '&' with '&' in XML file?

I need to find solution to fix by using XSLT 1! Most of sent XML files well formatted and someone make mess by adding characters (& < >. . .). Any way to do replace this on my side? I tried XSLT 2 and Replace function does not work as I use XSLT processor from Microsoft
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:saxon="http://saxon.sf.net/"
exclude-result-prefixes="xs saxon"
version="2.0">
<xsl:param name="path" select="'file:///E:/foo.xml'"></xsl:param>
<xsl:template match="/">
<xsl:copy-of select="unparsed-text($path)"></xsl:copy-of>
<xsl:copy-of select="saxon:parse(replace(unparsed-text($path), '&', '&amp;'))"/>
</xsl:template>
</xsl:stylesheet>
Any other suggestion how to solve this issue. for example I have input XML file like:
<?xml version="1.0" encoding="UTF-8"?>
<name>Stack & Exchange</name>
And is fail on '&' character.
Please advice!
Thank you
Conclusion
Two observations
XSLT requires at least a well formed XML document at the input, so I can't use it to correct invalid XML
(it is an XML transformation language)
in order to use replace or escape invalid characters of XML on input I need to make sure that I use an XSLT 2.0 processor
(I use Microsoft processor XSLT 1.0)
I see two options
If I receive an error on input, investigate and validate manually and send back the error message. - THIS IS I TRIED TO AVOID! (Use text tools like notepad++, excel to find an issue).
write a correcting parser in the .net language to fix before loading as XML

Can we declare global variable and add/Remove/Check value from it?

I want to achieve
Declare global variable having no value
<xsl:variable name="IsEqual"/>
Check variable value and change according to condition
<xsl:choose>
**// Checking value equal or not**
<xsl:when test="name=$name">
<xsl:choose>
**//Checking variable value**
<xsl:when test="$IsEqual !='Unequal'">
**//Setting variable value**
<xsl:variable name="IsEqual" Select="Equal"/>
</xsl:when>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
**//Setting variable value**
<xsl:variable name="IsEqual" Select="Unequal"/>
</xsl:otherwise>
</xsl:choose>
<xsl:value-of select="$IsEqual"/>
Expected output value of variable $IsEqual.. IF it is not possible then what is another way to achieve this? What should I use instead of variable?
"It's not a bug, it's a feature": XSLT variables are designed not to be changeable. Actually they could be named constants. Working around that is difficult, it can be done using parameters. In most cases that isn't necessary if you use the XSLT programming attempt, where the programm is driven by the data through templates.
The answer to your question is no.
Copied this (own) text from XML and Variables
#Sam: What do you want to accomplish using a global variable? Where do you want to check for equality? I have no idea what you want to do so I can only give you a general example.
Try this xml file:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="test.xsl"?>
<root>
<data check="value1">This is data 1</data>
<data check="value2">This is data 2</data>
<data check="value3">This is data 3</data>
</root>
with this xslt file:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="v">value2</xsl:variable>
<xsl:template match="/">
<xsl:apply-templates select="root/data[#check = $v]"/>
</xsl:template>
<xsl:template match="data">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
Only the second data element will show up as this one matches the global variable, which stays the same all the time. If you want different values to match with, you can put them into your data file instead using a variable and compare the different elements.
For testing just save the two files (test.xml and test.xsl) into one directory and open test.xml with your browser.
#Sam again: As you insist on changing an xslt variable I have to repeat that this can't be done. Maybe there is a way around using the environment xslt is running in. E.g. PHP, where you can pass functions into the script. I described the technique here: Can PHP communicate with XSLT?
The xslt spec says:
XSLT does not provide an equivalent to the Java assignment operator
x = "value";
because this would make it harder to create an implementation that processes a document other than in a batch-like way, starting at the beginning and continuing through to the end.
(See http://www.w3.org/TR/xslt#variables to prove my answer "no" to your question is correct :-)