Trying to remove ^M. I am not sure whether this can be done via XSLT or regress.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" >^M
<soapenv:Header>^M
</soapenv:Header>^M
<soapenv:Body>^M
<urn:getTargetingInfo>^M
<getTargetingInfoRequest>^M
<inCID>202020</inCID>^M
<inAttributeType/>^M
</getTargetingInfoRequest>^M
</urn:getTargetingInfo>^M
</soapenv:Body>
</soapenv:Envelope>
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="text()[starts-with(., '^M')]"/>
</xsl:stylesheet>
Related
I need to remove some unwanted fields over a big response XML using XSL 1.0, and want to use apply-templates instead of for-each. Below is the code I tried but is not giving expected results i.e., unwanted fields are removed successfully but few other fields outside match also disappeared. Am I using identity template incorrectly.
Input XML:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:object xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:array name="BankDetails">
<one>field1</one>
<two>field2</two>
<xsl:object>
<date>1234-56-78</date>
<Time>12345678</Time>
</xsl:object>
<xsl:object>
<date>0000-00-00</date>
<Time>00000000</Time>
</xsl:object>
<xsl:object>
<date>0000-00-00</date>
<Time>00000000</Time>
</xsl:object>
<xsl:object>
<date>0000-00-00</date>
<Time>00000000</Time>
</xsl:object>
<three>field3</three>
<four>field4</four>
<five>field5</five>
<six>field6</six>
</xsl:array>
</xsl:object>
Applied XSLT:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias"
xmlns:str="http://exslt.org/strings">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
<xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl" />
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="xsl:object/xsl:array">
<xsl:for-each select="xsl:object[Time !='00000000']">
<xsl:copy-of select = "."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
What I got:
<?xml version="1.0" encoding="UTF-8"?><xsl:object xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:object>
<date>1234-56-78</date>
<Time>12345678</Time>
</xsl:object>
</xsl:object>
What is expected:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:object xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:array name="BankDetails">
<one>field1</one>
<two>field2</two>
<xsl:object>
<date>1234-56-78</date>
<Time>12345678</Time>
</xsl:object>
<three>field3</three>
<four>field4</four>
<five>field5</five>
<six>field6</six>
</xsl:array>
</xsl:object>
The problem with your attempt is that you are copying only xsl:object elements that have the right Time - but not doing anything (i.e. copy or apply templates) for the other elements that are also children of the context xsl:array element (one, two etc). If you do not apply templates to them, then the identity transform template will not be applied to them.
You are also not copying the context xsl:array element.
I would suggest you approach it from the opposite point-of-view:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl" />
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="xsl:object[Time ='00000000']"/>
</xsl:stylesheet>
I need some tip here.
I have this XML:
<?xml version="1.0" encoding="UTF-8"?>
<A_Product>
<A_ProductType>
<to_Description>
<A_ProductDescriptionType>
<Language>DE</Language>
<ProductDescription>Handelsware 14, PD, Zukauf, H14</ProductDescription>
</A_ProductDescriptionType>
<A_ProductDescriptionType>
<Language>EN</Language>
<ProductDescription>Trad.Good 14,PD,Bought-In,H14</ProductDescription>
</A_ProductDescriptionType>
<A_ProductDescriptionType>
<Language>PT</Language>
<ProductDescription>TESTE OPERADOR WMS 2021</ProductDescription>
</A_ProductDescriptionType>
<A_ProductDescriptionType>
<Language>ES</Language>
<ProductDescription>MercaderÃa 14, PD, comprado, H14</ProductDescription>
</A_ProductDescriptionType>
</to_Description>
<to_Plant>
<A_ProductPlantType>
<Plant>M016</Plant>
<SerialNumberProfile>0001</SerialNumberProfile>
</A_ProductPlantType>
<A_ProductPlantType>
<Plant>S039</Plant>
<SerialNumberProfile>0001</SerialNumberProfile>
</A_ProductPlantType>
<A_ProductPlantType>
<Plant>T161</Plant>
<SerialNumberProfile>0001</SerialNumberProfile>
</A_ProductPlantType>
<A_ProductPlantType>
<Plant>T191</Plant>
<SerialNumberProfile>0001</SerialNumberProfile>
</A_ProductPlantType>
</to_Plant>
</A_ProductType>
</A_Product>
I'm doing already the filter based on language 'PT' but also I need exclude all <A_ProductPlantType> that is different of value from PARAM array.
How to make it ?
XSLT:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:param name="Centros" select="T191,M016"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//A_ProductDescriptionType[Language!='PT']"/>
<xsl:template match="//A_ProductPlantType[Plant!=$Centros]"/>
</xsl:transform>
Current result, exclude all from <to_Plant> and this is not correct, should return the values contain in the PARAM, in this case:
<to_Plant>
<A_ProductPlantType>
<Plant>M016</Plant>
<SerialNumberProfile>0001</SerialNumberProfile>
</A_ProductPlantType>
<A_ProductPlantType>
<Plant>T191</Plant>
<SerialNumberProfile>0001</SerialNumberProfile>
</A_ProductPlantType>
</to_Plant>
You have several mistakes, among them having a param that contains a reference instead of a string. Also, in XSLT 1.0 you cannot use a variable or a param in a match pattern.
Try it along these lines:
<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:param name="Centros">T191,M016</xsl:param>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="A_ProductDescriptionType[Language!='PT']"/>
<xsl:template match="A_ProductPlantType">
<xsl:if test="contains(concat(',', $Centros, ','), concat(',', Plant, ','))">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
In XSLT-2.0 you could make use of a sequence for the param match:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:param name="Centros" select="('T191','M016')"/> <!-- Sequence -->
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="to_Description//A_ProductDescriptionType[Language!='PT']"/>
<xsl:template match="to_Plant//A_ProductPlantType[Plant=$Centros]"/>
</xsl:transform>
But in XSLT-1.0, this is more complicated, because
Variable references in match patterns are not allowed by XSLT 1.0, but they are allowed in XSLT 2.0
So you have to invert the logic like this:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:param name="Centros1" select="'T191'"/> <!-- One value per parameter -->
<xsl:param name="Centros2" select="'M016'"/> <!-- One value per parameter -->
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="to_Description//A_ProductDescriptionType[Language!='PT']"/>
<xsl:template match="to_Plant//A_ProductPlantType">
<xsl:if test="Plant!=$Centros1 and Plant!=$Centros2"><xsl:copy><xsl:apply-templates select="node()|#*" /></xsl:copy></xsl:if>
</xsl:template>
</xsl:transform>
The output in both cases should be the same:
<A_Product>
<A_ProductType>
<to_Description>
<A_ProductDescriptionType>
<Language>PT</Language>
<ProductDescription>TESTE OPERADOR WMS 2021</ProductDescription>
</A_ProductDescriptionType>
</to_Description>
<to_Plant>
<A_ProductPlantType>
<Plant>S039</Plant>
<SerialNumberProfile>0001</SerialNumberProfile>
</A_ProductPlantType>
<A_ProductPlantType>
<Plant>T161</Plant>
<SerialNumberProfile>0001</SerialNumberProfile>
</A_ProductPlantType>
</to_Plant>
</A_ProductType>
</A_Product>
If you want to pass several strings as parameters delimited by commas, you could create an xsl:for-each loop iterating over each substring - which would be quite complicated.
You could do it this way :
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:param name="Centros" select="'T191,M016'"/>
<xsl:strip-space elements="*"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="A_ProductDescriptionType[Language!='PT']"/>
<xsl:template match="A_ProductPlantType[not(contains($Centros,Plant))]"/>
</xsl:transform>
You need to add single quotes to your "Centros" string.
Also I would advise that you declare your string something like this : "'|T191|,|M016|'" in order to avoid substrings of your codes being taken into account.
Then change your template to:
<xsl:template match="A_ProductPlantType[not(contains($Centros,concat('|',Plant,'|'))]"/>
when I execute the below stylesheet
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|#*" >
<xsl:copy>
<xsl:variable name="manu" select="node()|#*"/>
<xsl:apply-templates select="$manu"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I'm getting the below output:-
<?xml version="1.0" encoding="UTF-8" ?>
<A1>
<B1>
<FILES>
<StudentData>
<Student>0001</Student>
<Student>0002</Student>
</StudentData>
</FILES>
</B1>
</A1>
Now I want to select only the StudentData:-
Expected Output:-
<StudentData>
<Student>0001</Student>
<Student>0002</Student>
</StudentData>
How to match this in XSLT?
There a lots of ways. i.e. you could match on root and then just do a copy of the element using the xpath to that element like this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/">
<xsl:copy-of select="A1/B1/FILES/StudentData"/>
</xsl:template>
</xsl:stylesheet>
Why using an identity template? As far as I understand your problem, the simple solution is this:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="StudentData" >
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
If you want to filter the empty lines out of your output, add a template matching the text nodes for that purpose:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="StudentData" >
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="text()"/>
<!-- this tricky template prevents empty white lines in output -->
</xsl:stylesheet>
I need to ensure that the empty tags (except the mandatory fields)be excluded from the output. The mandatory fields should be in the output even if they are empty
Using the following xslt, I am able to exclude the empty tags. But even the mandatory fields, if they are empty are removed from the output. Please advise.
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes" method="xml"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match= "*[not(#*|*|comment()|processing-instruction()) and
normalizespace()='']"/>
</xsl:stylesheet>
Change
<xsl:template match= "*[not(#*|*|comment()|processing-instruction()) and
normalizespace()='']"/>
to
<xsl:template match= "*[not(#*|*|comment()|processing-instruction()) and
normalizespace()='' and not(self::foo | self::bar | self::foobar)]"/>
where you replace foo, bar, foobar with the names of your mandatory elements.
I think you only can end up naming the elements you want to remove:
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes" method="xml"/>
<xsl:strip-space elements="*"/>
<!-- Identity template -->
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<!-- Remove the following elements -->
<xsl:template match="element1 | element2 | element3"/>
</xsl:stylesheet>
My problem is how to add namespace and prefix for all elements and attributes using XSLT?
My input xml as is....
<ProcessCreditMemo xmlns='CreditMemo'
xmlns:xsd='http://www.w3.org/2001/XMLSchema'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>
<ORDER_HEADERDetails>
<ORDER_HEADER>
<NAME>0010185214</NAME>
to be...
<ns0:ProcessCreditMemo xmlns='CreditMemo'
xmlns:xsd='http://www.w3.org/2001/XMLSchema'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'
xmlns:ns0="http://tempuri.org/">
<ns0:ORDER_HEADERDetails>
<ns0:ORDER_HEADER>
<ns0:NAME>0010185214</NAME>
I need add the prefix "ns0:" for all elements and attributes, and add the namespace "xmlns:ns0="http://tempuri.org/" in the header "ProcessCreditMemo".
I am trying to build a XSLT to do it...
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="node()|text()|#*">
<xsl:copy>
<xsl:if test="local-name()='ProcessCreditMemo'">
<xsl:attribute name="xmlns" namespace="http://tempuri.org/" />
</xsl:if>
but the resulting XML duplicates the prefix with empty value.
<ProcessCreditMemo xmlns="CreditMemo"
xmlns:ns0="http://tempuri.org/"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
ns0:xmlns="">
This transformation:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="http://tempuri.org/">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<xsl:element name="ns0:{name()}" namespace="http://tempuri.org/">
<xsl:copy-of select="namespace::*"/>
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
when applied on the (corrected) provided input (severely malformed, incomplete XML):
<ProcessCreditMemo xmlns='CreditMemo'
xmlns:xsd='http://www.w3.org/2001/XMLSchema'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'>
<ORDER_HEADERDetails>
<ORDER_HEADER>
<NAME>0010185214</NAME>
</ORDER_HEADER>
</ORDER_HEADERDetails>
</ProcessCreditMemo>
produces the wanted, correct result (not the severely malformed/incomplete provided wanted-result):
<ns0:ProcessCreditMemo xmlns:ns0="http://tempuri.org/" xmlns="CreditMemo" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<ns0:ORDER_HEADERDetails>
<ns0:ORDER_HEADER>
<ns0:NAME>0010185214</ns0:NAME>
</ns0:ORDER_HEADER>
</ns0:ORDER_HEADERDetails>
</ns0:ProcessCreditMemo>