subsequent element as attribute in xml using xslt - java

need help in making subsequent element as attribute to preceding element if subsequent element contains the preceding element name using XSLT.
For below example, <emp_id> contains the preceding the element name so need to convert this element as attribute to element. can you anyone help for this?. I tried using subsequent functions in xslt but not working. Thanks in advance.
Sample XML:
<root>
<emp>test</emp>
<emp_id>1234</emp_id>
<college>something</college>
</root>
Expected out:
<root>
<emp id="1234">test</emp>
<college>something</college>
</root>

In the given example, you could do:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:apply-templates select="following-sibling::*[starts-with(name(), name(current()))]" mode="attr"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="*" mode="attr">
<xsl:attribute name="{substring-after(name(), '_')}">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
<xsl:template match="*[preceding-sibling::*[name()=substring-before(name(current()), '_')]]"/>
</xsl:stylesheet>
to achieve the expected result.
There is probably a more elegant way, but we need to have some more rules, not just a single example.
Added:
Assuming that every element whose name contains a _ has a "parent" element whose attribute it should become, you can start by applying templates to only the "parent" elements (i.e. elements whose name does not contain a '_').
Then use a key to collect the "child" elements that need to be converted to attributes.
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="atr" match="*" use="substring-before(name(), '_')" />
<xsl:template match="/root">
<xsl:copy>
<xsl:apply-templates select="*[not(contains(name(), '_'))]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:for-each select="key('atr', name())">
<xsl:attribute name="{substring-after(name(), '_')}">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:for-each>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

Related

Replace element tag to empty tag

My requirements is to generate an empty element with the given scenario. I have the same in this Replacing the element tag with value to end tag. However, the output generated is not what I am expecting.
CONDITION:
Map according to priority:
1. If Test1 is equal to Payment1, generate this empty element <st:Test1/> 2. else if Test2 is equal to Payment2, generate this empty element <st:Test2/> 3. else if Test3 is equal to Payment3, generate this empty element <st:Test3/>.
MY XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:st="http://www.ebinterface.at/schema/4p1/" xmlns:po="http://schema.ebinterface.at/schema/4p1/" exclude-result-prefixes="po">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:element name="st:{local-name()}">
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
<xsl:template match="po:DEFG" priority="1">
<st:DEFG>
<!--handle any existing child content-->
<xsl:apply-templates select="#* | node()"/>
<xsl:if test="not(po:Test1)">
<xsl:call-template name="Test1"/>
</xsl:if>
<xsl:if test="not(po:Test2)">
<xsl:call-template name="Test2"/>
</xsl:if>
<xsl:if test="not(po:Test3)">
<xsl:call-template name="Test3"/>
</xsl:if>
</st:DEFG>
</xsl:template>
<xsl:template match="po:Test1[.='Payment1']" name="Test1" priority="1">
<st:Test1/>
</xsl:template>
<xsl:template match="po:Test2[.='Payment2']" name="Test2" priority="1">
<st:Test2/>
</xsl:template>
<xsl:template match="po:Test3[.='Payment3']" name="Test3" priority="1">
<st:Test3/>
</xsl:template>
<xsl:template match="*[namespace-uri()='http://www.ebinterface.at/schema/4p1/']">
<xsl:element name="po:{local-name()}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="*[namespace-uri()='http://www.ebinterface.at/schema/4p1/']/#*">
<xsl:attribute name="po:{local-name()}"><xsl:value-of select="."/></xsl:attribute>
</xsl:template>
</xsl:stylesheet>
INPUT FILE:
<?xml version="1.0" encoding="UTF-8"?>
<Statistics xmlns="http://schema.ebinterface.at/schema/4p1/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.ebinterface.at/schema/4p1/" Type="abc" Title="Statistics">
<ABC dsig="fh">Sample ABC</ABC>
<DEFG>
<Note>Wir ersuchen um termingerechte Bezahlung.</Note>
<Amount currencyCode="EUR">12.36</Amount>
<Test1>Payment1</Test1>
</DEFG>
</Statistics>
GENERATED OUTPUT:
<?xml version="1.0" encoding="UTF-8"?>
<st:Statistics xmlns:st="http://www.ebinterface.at/schema/4p1/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.ebinterface.at/schema/4p1/" Type="abc" Title="Statistics">
<st:ABC dsig="fh">Sample ABC</st:ABC>
<st:DEFG>
<st:Note>Wir ersuchen um termingerechte Bezahlung.</st:Note>
<st:Amount currencyCode="EUR">12.36</st:Amount>
<st:Test1/>
<st:Test2/> **This empty element should not appear since there's no Test2=Payment2**
<st:Test3/> **This empty element should not appear since there's no Test3=Payment3**
</st:DEFG>
</st:Statistics>
EXPECTED OUTPUT:
<?xml version="1.0" encoding="UTF-8"?>
<st:Statistics xmlns="http://schema.ebinterface.at/schema/4p1/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.ebinterface.at/schema/4p1/" st:Type="abc" st:Title="Statistics">
<st:ABC st:dsig="fh">Sample ABC</st:ABC>
<st:DEFG>
<st:Note>Wir ersuchen um termingerechte Bezahlung.</st:Note>
<st:Amount st:currencyCode="EUR">12.36</st:Amount>
<st:Test1/>
</st:DEFG>
</stStatistics>
Thank you in advance.
Your response is greatly appreciated.
When you call a template by name, that template will be executed regardless of whether it matches anything or not.
Not directly related to your question, you also have a template conflict between <xsl:template match="#* | node()"> and <xsl:template match="*">. Overall, you have way too much code; I believe you could do with just:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:po="http://schema.ebinterface.at/schema/4p1/"
xmlns:st="http://www.ebinterface.at/schema/4p1/"
exclude-result-prefixes="po">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- move elements to new namespace -->
<xsl:template match="*">
<xsl:element name="st:{local-name()}">
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
<!-- move attributes to new namespace -->
<xsl:template match="#*">
<xsl:attribute name="st:{local-name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
<!-- except attributes that are NOT in the default namespace -->
<xsl:template match="#*[namespace-uri()]">
<xsl:copy/>
</xsl:template>
<xsl:template match="po:Test1[.='Payment1']">
<st:Test1/>
</xsl:template>
<xsl:template match="po:Test2[.='Payment2']">
<st:Test2/>
</xsl:template>
<xsl:template match="po:Test3[.='Payment3']">
<st:Test3/>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<st:Statistics xmlns:st="http://www.ebinterface.at/schema/4p1/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.ebinterface.at/schema/4p1/" st:Type="abc" st:Title="Statistics">
<st:ABC st:dsig="fh">Sample ABC</st:ABC>
<st:DEFG>
<st:Note>Wir ersuchen um termingerechte Bezahlung.</st:Note>
<st:Amount st:currencyCode="EUR">12.36</st:Amount>
<st:Test1/>
</st:DEFG>
</st:Statistics>
Note:
The three choices are not mutually exclusive as your question would suggest.
Your expected output is not well-formed XML: you cannot have a prefix without binding it to a namespace.

Customizing/Remove name space in Soap Response - JAX-WS [duplicate]

I need to remove the namespace prefix from an un-SOAP'd message.
This is the message that has had the SOAP envelope removed. As you can see it contains ns1 prefix on the elements:
<ns1:BookingSource xmlns:ns1="urn:EDI/Booking/artifacts">
<ns1:BookingHeader>
<ns1:BookingNo>000123</ns1:BookingNo>
<ns1:BookingDate>01/01/2012</ns1:BookingDate>
<ns1:DSBookingDetail>
<ns1:BookingNo>000123</ns1:BookingNo>
<ns1:SeqNo>1</ns1:SeqNo>
<ns1:LineType>Item</ns1:LineType>
<ns1:ProductCode>Box</ns1:ProductCode>
</ns1:DSBookingDetail>
<ns1:DSBookingDetail>
<ns1:BookingNo>000123</ns1:BookingNo>
<ns1:SeqNo>2</ns1:SeqNo>
<ns1:LineType>Item</ns1:LineType>
<ns1:ProductCode>BrakeShoe</ns1:ProductCode>
</ns1:DSBookingDetail>
</ns1:DSBookingHeader>
<ns1:BookingHeader>
<ns1:BookingNo>000124</ns1:BookingNo>
<ns1:BookingDate>01/01/2012</ns1:BookingDate>
<ns1:DSBookingDetail>
<ns1:BookingNo>000124</ns1:BookingNo>
<ns1:SeqNo>1</ns1:SeqNo>
<ns1:LineType>Item</ns1:LineType>
<ns1:ProductCode>Box</ns1:ProductCode>
</ns1:DSBookingDetail>
<ns1:DSBookingDetail>
<ns1:BookingNo>000124</ns1:BookingNo>
<ns1:SeqNo>2</ns1:SeqNo>
<ns1:LineType>Item</ns1:LineType>
<ns1:ProductCode>BrakeShoe</ns1:ProductCode>
</ns1:DSBookingDetail>
</ns1:DSBookingHeader>
</ns1:BookingSource>
To this:
<BookingSource>
<BookingHeader>
<BookingNo>000123</BookingNo>
<BookingDate>01/01/2012</BookingDate>
<DSBookingDetail>
<BookingNo>000123</BookingNo>
<SeqNo>1</SeqNo>
<LineType>Item</LineType>
<ProductCode>Box</ProductCode>
</DSBookingDetail>
<DSBookingDetail>
<BookingNo>000123</BookingNo>
<SeqNo>2</SeqNo>
<LineType>Item</LineType>
<ProductCode>BrakeShoe</ProductCode>
</DSBookingDetail>
</DSBookingHeader>
<BookingHeader>
<BookingNo>000124</BookingNo>
<BookingDate>01/01/2012</BookingDate>
<DSBookingDetail>
<BookingNo>000124</BookingNo>
<SeqNo>1</SeqNo>
<LineType>Item</LineType>
<ProductCode>Box</ProductCode>
</DSBookingDetail>
<DSBookingDetail>
<BookingNo>000124</BookingNo>
<SeqNo>2</ns1:SeqNo>
<LineType>Item</LineType>
<ProductCode>BrakeShoe</ProductCode>
</DSBookingDetail>
</DSBookingHeader>
</BookingSource>
I've searched through the KB and found some hints on how to do it, but the final solution evades me.
Thanks,
Tony.
It is called namespace, below is a code to remove namespace from all elements and attributes ..
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="*">
<xsl:element name="{local-name(.)}">
<xsl:apply-templates select="#* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="#*">
<xsl:attribute name="{local-name(.)}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>

Parsing nested XML File as node set

I have a problem. I have an xml file as below :
Main.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<msrsw>
<software>
<chapter>
<name> Hello world</sample>
<xref type="xml">C:\ABC\NestedXML.xml</xref>
</chapter>
</software>
</msrsw>
NestedXml.xml :
<?xml version="1.0" encoding="ISO-8859-1"?>
<msrsw>
<software>
<chapter>
<name> Nested XML </sample>
<age>14</age>
<country>Canada</country>
</chapter>
</software>
</msrsw>
I am using Apache FOP to produce PDF document (Using Java). FOP needs src and dest params. Src being Main.xml.
My XSLT is as below:
<xsl:param name="xmlFileName" />
<xsl:param name="XMLFile" select="document($xmlFileName)"/>
<xsl:template name="Chapters_1_2_Template">
<xsl:apply-templates select="$XMLFile/*" mode="chapter" />
</xsl:template>
<xsl:template match="node()" mode="chapter">
<xsl:for-each select="node()">
<xsl:if test="current()[name() = 'xref']">
<xsl:apply-templates select="current()[name() = 'xref']" mode="x" />
</xsl:if>
<xsl:if test="current()[name() = 'name']">
<xsl:apply-templates select="current()[name() = 'name']" mode="name" />
</xsl:if>
<xsl:if test="current()[name() = 'age']">
<xsl:apply-templates select="current()[name() = 'age']" mode="age" />
</xsl:if>
</xsl:for-each>
</xsl:template>
<xsl:template match="name" mode="name">
<xsl:value-of select="current()" />
</xsl:template>
<xsl:template match="age" mode="age">
<xsl:value-of select="current()" />
</xsl:template>
<xsl:template match="country" mode="country">
<xsl:value-of select="current()" />
</xsl:template>
<xsl:template match="xref" mode="x">
<xsl:param name="XMLFile" select="document(current())"/>
<xsl:call-template name="Chapters_1_2_Template" />
</xsl:template>
When I execute the above code, i get the following error in the line <xsl:apply-templates select="$XMLFile/*" mode="chapter" />:
Invalid token XMLFile.
When I remove $XMLFile - <xsl:apply-templates select="*" mode="chapter" /> , it works fine for me with Main.xml file's content.
When I just display the value of current() in xref template, it is parses the NestedXml.xml file and displayes string values in PDF.
Expected Output is:
Hello world
Nested XML
14
Canada
My requirement is to embed the node-set of NestedXML.xml within the<xref></xref> tags and recursively applyTemplates on that node-set.
But the document() function gives me the parsed String content of NestedXml.xml.
I do not want to use the document() function and just get the String value of NestedXml.xml. I need to parse all the tags of NestedXml.xml using the same XSLT.
Please suggest me where am I going wrong. Is this approach right? Is there any other way to do this?
Or it is not possible to do in this way using XSLT and that XSLT allows including only the parsed String values?
If it is that you want just some text nodes, the stylesheet needn't be that complex. Try this simpler stylesheet:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="text" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:apply-templates select="msrsw/software/chapter/name"/>
<xsl:apply-templates select="document(msrsw/software/chapter/xref)/*"/>
</xsl:template>
<xsl:template match="text()">
<xsl:value-of select="normalize-space()"/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>

CDATA XML masking with XSLT should return same XML with few masked fields

I have a requirement of masking few fields in XML of CDATA inside XML with XSLT.
So the resultant XML should be same like the input XML but few fileds are masked with XSLT.
I followed this link which is masking as expected but producing XML is in different format.
I tried many other solutions from SO, they are almost outputing the new XML/HTML in other format which is different from the input XML.
Please check the following example for better understading.
Input XML with CDATA content.
<XML>
<LogLevel>info</LogLevel>
<Content><![CDATA[ <Msg>
<AccountNo>2701000098983</AccountNo>
<ApplName>Testing</ApplName>
</Msg>]]></Content>
<Date>20140909</Date>
</XML>
Output XML should be:
<XML>
<LogLevel>info</LogLevel>
<Content><![CDATA[ <Msg>
<AccountNo>XXXXXXXXXX983</AccountNo>
<ApplName>Testing</ApplName>
</Msg>]]></Content>
<Date>20140909</Date>
</XML>
Edit:
I used the following XSLT
<xsl:template match="node()">
<xsl:copy>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<xsl:choose>
<xsl:when test="contains(.,'<AccountNo>')">
<!-- This is the CDATA that I want to mask and write back out as CDATA -->
<xsl:variable name="tcontent">
<xsl:value-of
select="substring-after(substring-before(.,'</AccountNo>'),'<AccountNo>') " />
</xsl:variable>
<xsl:text disable-output-escaping="yes"><![CDATA[<AccountNo></xsl:text>
<xsl:call-template name="maskVariable">
<xsl:with-param name="tvar" select="$tcontent" />
</xsl:call-template>
<xsl:text disable-output-escaping="yes"></AccountNo>]]></xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:copy />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="maskVariable">
<xsl:param name="tvar" />
<xsl:variable name="length" select="string-length($tvar)" />
<xsl:choose>
<xsl:when test="$length > 3">
<xsl:value-of
select="concat ('************', substring($tvar,$length - 1, 2))" />
</xsl:when>
<xsl:when test="$length > 1">
***
</xsl:when>
<xsl:otherwise />
</xsl:choose>
</xsl:template>
Output of using this XSLT is :
<LogLevel>info</LogLevel>
<Content><![CDATA[<AccountNo>************02</AccountNo>]]></Content>
<Date>20140909</Date>
Here in output, only masked output of is displaying.
How to make other part of the code to get displayed ?
Please give me some idea how to do it ?
Any help is highly appreciated.
Why don't you try:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Content">
<xsl:copy>
<xsl:value-of select="substring-before(.,'<AccountNo>')" />
<xsl:text><AccountNo></xsl:text>
<xsl:variable name="acct-num" select="substring-before(substring-after(.,'<AccountNo>'), '</AccountNo>')" />
<xsl:value-of select="concat('************', substring($acct-num, string-length($acct-num) - 2))" />
<xsl:text></AccountNo></xsl:text>
<xsl:value-of select="substring-after(.,'</AccountNo>')" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Applied to your input, the result will be:
<?xml version="1.0" encoding="UTF-8"?>
<XML>
<LogLevel>info</LogLevel>
<Content> <Msg>
<AccountNo>************983</AccountNo>
<ApplName>Testing</ApplName>
</Msg></Content>
<Date>20140909</Date>
</XML>
Alternatively, you could use:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" cdata-section-elements="Content"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Content">
<xsl:copy>
<xsl:variable name="content">
<xsl:value-of select="substring-before(.,'<AccountNo>')" />
<xsl:text><AccountNo></xsl:text>
<xsl:variable name="acct-num" select="substring-before(substring-after(.,'<AccountNo>'), '</AccountNo>')" />
<xsl:value-of select="concat('************', substring($acct-num, string-length($acct-num) - 2))" />
<xsl:text></AccountNo></xsl:text>
<xsl:value-of select="substring-after(.,'</AccountNo>')" />
</xsl:variable>
<xsl:value-of select="$content" disable-output-escaping="yes"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
to produce:
<?xml version="1.0" encoding="UTF-8"?>
<XML>
<LogLevel>info</LogLevel>
<Content><![CDATA[ <Msg>
<AccountNo>************983</AccountNo>
<ApplName>Testing</ApplName>
</Msg>]]></Content>
<Date>20140909</Date>
</XML>
although this might not work with every processor (tested to work with Xalan 2.7.1: http://xsltransform.net/jyH9rMk).
The stuff inside the CDATA section is XML disguised as text. XSLT is good at transforming XML, it's not so good at transforming text, especially text with a complex grammar. So my approach would be: extract the text from the outer XML document, parse it as XML, transform it using XSLT (real XSLT that works on nodes rather than on markup), serialize it back to text, then stuff the text back into the original (outer) XML document.
Raw XSLT 1.0 can't do this within a single stylesheet. You need the functions parse() and serialize() to turn lexical XML into a node tree, and back again. These are available as extensions in some processors (such as Saxon), they become available as standard functions in XPath 3.0, and they can be written as simple extension functions (e.g. in Javascript) code in most other processors.

Write at the end of an xml

i have multiple Xml files, in a List<File>. What i want is to transform those xml into one Xml with an Xsl :
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="testsuites">
<xsl:call-template name="summary"/>
</xsl:template>
<xsl:template name="summary">
<xsl:variable name="testCount" select="sum(testsuite/#tests)"/>
<xsl:variable name="errorCount" select="sum(testsuite/#errors)"/>
<xsl:variable name="failureCount" select="sum(testsuite/#failures)"/>
<xsl:variable name="timeCount" select="sum(testsuite/#time)"/>
<xsl:variable name="successRate" select="($testCount - $failureCount - $errorCount) div $testCount"/>
<xsl:attribute name="class">
<xsl:choose>
<xsl:when test="$failureCount > 0">Failure</xsl:when>
<xsl:when test="$errorCount > 0">Error</xsl:when>
</xsl:choose>
</xsl:attribute>
<Build>
<NombreTest><xsl:value-of select="$testCount"/></NombreTest>
<Failures><xsl:value-of select="$failureCount"/></Failures>
<Erreurs><xsl:value-of select="$errorCount"/></Erreurs>
<PercentSucces><xsl:call-template name="display-percent">
<xsl:with-param name="value" select="$successRate"/>
</xsl:call-template></PercentSucces>
<ExecTime><xsl:call-template name="display-time">
<xsl:with-param name="value" select="$timeCount"/>
</xsl:call-template> </ExecTime>
</Build>
</xsl:template>
<xsl:template match="failure">
<xsl:call-template name="display-failures"/>
</xsl:template>
<xsl:template match="error">
<xsl:call-template name="display-failures"/>
</xsl:template>
<xsl:template name="display-time">
<xsl:param name="value"/>
<xsl:value-of select="format-number($value,'0.000')"/>
</xsl:template>
<xsl:template name="display-percent">
<xsl:param name="value"/>
<xsl:value-of select="format-number($value,'0.00%')"/>
</xsl:template>
<xsl:template name="display-failures">
<xsl:choose>
<xsl:when test="not(#message)">N/A</xsl:when>
<xsl:otherwise>
<xsl:value-of select="#message"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
My problem is that when i am looping and apply the transform with a TransformerFactory it always erase the output XML. I want to edit the output instead.
I know that i can do it in java with a temporary XML and after merge it, but i'm almost sure that it is possible in XSL?
Thanks for helping
You need to pass all document URLs within a single external parameter and you will typically have a transformation like this:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="pdocNames">
<name>doc1.xml</name>
<name>doc2.xml</name>
<name>doc3.xml</name>
</xsl:param>
<!-- you can directly use $pdocNames/name
if the param is provided externally -->
<xsl:variable name="vDocNames" select=
"document('')/*/xsl:param[]#name='pdocNames']/name"/>
<xsl:template match="/">
<combinedDocs>
<xsl:copy-of select="document($vDocNames)"/>
</combinedDocs>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on any XML document (not used), it performs the following:
Obtains the name elements that contain the provides in the parameter $pdocNames document URIs. These elements are contained in the variable vDocNames.
Creates the top element for the output document (in this case named combinedDocs).
Copies all XML documents, whose URIs are in the name elements contained in the vDocNames variable. The standard XSLT function document() is used here.
Do note:
The URLs of all wanted XML documents must be passed externally via a parameter to the transformation. It is vendor-dependent how to pass a parameter to the transformation. You need to read the documentation provided for your particular XSLT processor.
You have to load your documents with document(URI) XSLT function
See also: http://www.w3schools.com/Xsl/func_document.asp

Categories