Replace all tags below a node - xslt-1.0

I need to change all tags below a node in transformation.
Source XML looks like this:
<Address>
<s:name>name</s:name>
<s:lastName>last name <a:lastName>
<s:address1>Address Line 1</s:address1>
<s:address2>Address Line 2</s:address2>
Required O/p:
<Address>
<name>name</name>
<lastName>last name <lastName>
<address1>Address Line 1</address1>
<address2>Address Line 2</address2>
There are thousand of tags.So, can not write match to all. Is there a way I can take top level node and handle all tags below?

If you use match="/*//*" then you match all descendant elements of the root element. Then you can construct a new element using
<xsl:template match="/*//*"><xsl:element name="local-name()"><xsl:apply-templates select="#* | node ()"/></xsl:element></xsl:template>
Then add the identity transformation template to your code and you are done.

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+.

Consolidate document() dependencies into single XSLT

I need to consolidate external files into a single XSLT 1.0 file as a transformation is going to be performed in memory without access to the original file structure.
I cannot figure out how to merge in the files which are read into variables.
The original variable declaration looks like this. (the parameter pLang is needed in the select statement I have trouble with):
<xsl:param name="pLang" select="'no'"/>
<xsl:variable name="moduleDoc" select="document('Headlines.xml')"/>
I have filled the moduleDoc variable with the contents of the Headlines file like this:
<xsl:param name="pLang" select="'no'"/>
<xsl:variable name="moduleDoc">
<module xmlns:mmx="http://funx" xmlns:svg="http://www.w3.org/2000/svg" xmlns:fnc="http://funx/fnc" xmlns:att="http://funx/att" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<document-merge>
<g-funcs>
<g name="IssueDate">
<g-lang xml:lang="no">Fakturadato</g-lang>
<g-lang xml:lang="nn">Fakturadato</g-lang>
<g-lang xml:lang="en">Issue date</g-lang>
</g>
<!--snip -->
</g-funcs>
</document-merge>
</module>
</xsl:variable>
The select statement looks like this:
<xsl:value-of select="$moduleDoc/module/document-merge/g-funcs/g[#name='IssueDate']/g-lang[lang($pLang)]"/>
This works fine when the moduleDoc variable is referencing the external file, but after the merge I get a Saxon error:
To use a result tree fragment in a path expression, either use
exsl:node-set() or specify version='1.1'
What is the proper way to access these nodes in the variable?
I ffigured out that the solution is to use the node-set extension in such a way:
<xsl:value-of select="exsl:node-set($moduleDoc)/module/document-merge/g-funcs/g[#name='IssueDate']/g-lang[lang($pLang)]"/></b> 
A namespace declaration is also needed:
xmlns:exsl="http://exslt.org/common"

words don't break correctly

In a block I have a text. I have some trouble with the linefeedtreatment.
<fo:block>
<xsl:value-of select="text"/>
</fo:block>
The text Shows like this:
Master II Phase 1, Pha-
se 2, Phase 3
Must look like this:
Master II Phase 1,
Phase 2, Phase 3
I've tried "Keep-together.within-line" and "linefeed-treatment" but without any result.
You appear to have hyphenation enabled when you don't want it to be. Presumably your FO contains hyphenate="true" on some ancestor FO. See https://www.w3.org/TR/xsl11/#hyphenate
Add hyphenate="false" to the fo:block to disable hyphenation of the text in the block.
The other possibility is that you have soft-hyphen characters in your text. If hyphenate="false" doesn't solve the problem, please edit your question to add the XML for the text element that has the problem.

How to not escape special chars when updating XML in oracle SQL

I have a problem trying to update xmlType values in oracle.
I need to modify the xml looking similar to the following:
<a>
<b>Something to change here</b>
<c>Here is some narrative containing weirdly escaped <tags>\</tags> </c>
</a>
What I want to achieve is to modify <b/> without modifying <c/>
Unfortunately following modifyXml:
select
updatexml(XML_TO_MODIFY, '/a/b/text()', 'NewValue')
from dual;
returns this:
<a>
<b>NewValue</b>
<c>Here is some narrative containing weirdly escaped <tags></tags> </c>
</a>
as you can see, the '>' had been escaped.
Same happens for xmlQuery (the new non-deprecated version of updateXml):
select /*+ no_xml_query_rewrite */
xmlquery(
'copy $d := .
modify (
for $i in $d/a
return replace value of node $i/b with ''nana''
)
return $d'
passing t.xml_data
returning content
) as updated_doc
from (select xmlType('<a>
<b>Something to change here</b>
<c>Here is some narrative containing weirdly escaped \<tags>\</tags> </c>
</a>') as xml_data from dual) t
;
Also when using xmlTransform I will get the same result.
I tried to use the
disable-output-escaping="yes"
But it did the opposite - it unescaped the < :
select XMLTransform(
xmlType('<a>
<b>Something to change here</b>
<c>Here is some narrative containing weirdly escaped \<tags>\</tags> </c>
</a>'),
XMLType(
'<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/a/b">
<b>
<xsl:value-of select="text()"/>
</b>
</xsl:template>
<xsl:template match="/a/c">
<c>
<xsl:value-of select="text()" disable-output-escaping="yes"/>
</c>
</xsl:template>
</xsl:stylesheet>'))
from dual;
returned:
<a>
<b>NewValue</b>
<c>Here is some narrative containing weirdly escaped <tags></tags> </c>
</a>
Any suggestions?
Two things you need to know:
I cannot modify the initial format - it comes to me in this way and
I need to preserve it.
The original message is so big, that changing
the message to string and back (to use regexps as workaround) will
not do the trick.
The root of your issue seems to be that your original XML value for node C is not valid XML if it contains the > within the value instead of >, and not inside a CDATA section (also What does <![CDATA[]]> in XML mean?).
The string value of:
Here is some narrative containing weirdly escaped <tags>\</tags>
in XML format should really be
<c>Here is some narrative containing weirdly escaped &lt;tags>\&lt;/tags></c>
OR
<c><![CDATA[Here is some narrative containing weirdly escaped <tags>\</tags>]]></c>
I would either request that the XML be corrected at the source, or implement some method to sanitize the inputs yourself, such as wrapping the <c> node values in <![CDATA[]]>. If you need to save the exact original value, and the messages are large, then the best I can think of is the store duplicate copies, with the original value as string, and store the "sanitized" value as XML data type.
In the end we managed to do this with the help of java.
By:
reading the xml as a clob
modifying it in java
storing it back in the database using java.sql.Connection (for some reason, if we used
JdbcTemplate, it complained about casting to Long, which was
indication that string was over 4000 bytes (talking about clean
errors, all hail Oracle) and using CLOB Type didn't really
help. I guess it's a different story though)
When storing the data, oracle does not perform any magic, only updates tend to modify escape characters.
Possibly not an answer for everyone, but a nice workaround if you stumble upon same problem as we did.

Limitations of Eric van der Vlist's RelaxNG simplicification

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.