How to create 1 group to sum 4 elements with xslt - xslt

I am trying to use muenchian to do a group/sum, but I can't make it work.
Any help available?! :)
XML I have:
<RLA760910>
<G_L_By_Object_Account___Localization_S10>
<Zsz_ObjectAcctSub_OSBOW_ID3>401100.900</Zsz_ObjectAcctSub_OSBOW_ID3>
<SumBegBalance>-20</SumBegBalance>
<SumDebitPeriod>10</SumDebitPeriod>
<SumCreditPeriod>-5</SumCreditPeriod>
<SumEndBalance>-15</SumEndBalance>
</G_L_By_Object_Account___Localization_S10>
<G_L_By_Object_Account___Localization_S10>
<Zsz_ObjectAcctSub_OSBOW_ID3>401100.900</Zsz_ObjectAcctSub_OSBOW_ID3>
<SumBegBalance>100</SumBegBalance>
<SumDebitPeriod>10</SumDebitPeriod>
<SumCreditPeriod>-5</SumCreditPeriod>
<SumEndBalance>105</SumEndBalance>
</G_L_By_Object_Account___Localization_S10>
<Zsz_ObjectAcctSub_OSBOW_ID3>411100.900</Zsz_ObjectAcctSub_OSBOW_ID3>
<SumBegBalance>-30</SumBegBalance>
<SumDebitPeriod>5</SumDebitPeriod>
<SumCreditPeriod>-10</SumCreditPeriod>
<SumEndBalance>-35</SumEndBalance>
</G_L_By_Object_Account___Localization_S10>
<Zsz_ObjectAcctSub_OSBOW_ID3>451100.900</Zsz_ObjectAcctSub_OSBOW_ID3>
<SumBegBalance>80</SumBegBalance>
<SumDebitPeriod>20</SumDebitPeriod>
<SumCreditPeriod>-10</SumCreditPeriod>
<SumEndBalance>90</SumEndBalance>
</G_L_By_Object_Account___Localization_S10>
</RLA760910>
I've so far:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0"
<xsl:key name="AcctSub"
match="/RLA760910/G_L_By_Object_Account___Localization_S10"
use="#Zsz_ObjectAcctSub_OSBOW_ID3" />
<xsl:template match="Zsz_ObjectAcctSub_OSBOW_ID3">
<result>
<!-- Match the first acct element for a specific group -->
<xsl:apply-templates select="/RLA760910/G_L_By_Object_Account___Localization_S10/[generate-id() = generate-id(key('AcctSub', #Zsz_ObjectAcctSub_OSBOW_ID3)[1])]" />
</result>
</xsl:template>
<xsl:template match="/RLA760910/G_L_By_Object_Account___Localization_S10">
<total type="{#Zsz_ObjectAcctSub_OSBOW_ID3}">
<!-- Sum all the elements from the #type group -->
<xsl:value-of select="sum(key('AcctSub', #Zsz_ObjectAcctSub_OSBOW_ID3)/#Zsz_ObjectAcctSub_OSBOW_ID3)" />
</total>
</xsl:template>
</xsl:stylesheet>
Expected result will sum
SumBegBalance, SumDebitPeriod, SumCreditPeriod, SumEndBalance Group BY Zsz_ObjectAcctSub_OSBOW_ID3

Use the following script:
<?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" omit-xml-declaration="yes" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:key name="AcctSub"
match="G_L_By_Object_Account___Localization_S10"
use="Zsz_ObjectAcctSub_OSBOW_ID3"/>
<xsl:template match="RLA760910">
<xsl:copy>
<xsl:for-each select="*[generate-id()=generate-id(
key('AcctSub', Zsz_ObjectAcctSub_OSBOW_ID3)[1])]">
<result>
<xsl:variable name="Objects" select="key('AcctSub',
Zsz_ObjectAcctSub_OSBOW_ID3)"/>
<Zsz_ObjectAcctSub_OSBOW_ID3>
<xsl:value-of select="Zsz_ObjectAcctSub_OSBOW_ID3"/>
</Zsz_ObjectAcctSub_OSBOW_ID3>
<SumBegBalance>
<xsl:value-of select="sum($Objects/SumBegBalance)"/>
</SumBegBalance>
<SumDebitPeriod>
<xsl:value-of select="sum($Objects/SumDebitPeriod)"/>
</SumDebitPeriod>
<SumCreditPeriod>
<xsl:value-of select="sum($Objects/SumCreditPeriod)"/>
</SumCreditPeriod>
<SumEndBalance>
<xsl:value-of select="sum($Objects/SumEndBalance)"/>
</SumEndBalance>
</result>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
A few notes:
Zsz_ObjectAcctSub_OSBOW_ID3 is not an atribute but an element, so #
is not needed.
As the name of the root tag I used the same name as in your input.
Each result output tag contains Zsz_ObjectAcctSub_OSBOW_ID3 tag
(the grouping key) and sums of your 4 tags (within the group).

Try this as your starting point:
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:key name="grp" match="G_L_By_Object_Account___Localization_S10" use="Zsz_ObjectAcctSub_OSBOW_ID3" />
<xsl:template match="/RLA760910">
<result>
<xsl:for-each select="G_L_By_Object_Account___Localization_S10[generate-id() = generate-id(key('grp', Zsz_ObjectAcctSub_OSBOW_ID3)[1])]" >
<group type="{Zsz_ObjectAcctSub_OSBOW_ID3}">
<total-of-begbalance>
<xsl:value-of select="sum(key('grp', Zsz_ObjectAcctSub_OSBOW_ID3)/SumBegBalance)"/>
</total-of-begbalance>
<!-- add more totals here-->
</group>
</xsl:for-each>
</result>
</xsl:template>
</xsl:stylesheet>
When this is applied to the following well-formed example input:
XML
<RLA760910>
<G_L_By_Object_Account___Localization_S10>
<Zsz_ObjectAcctSub_OSBOW_ID3>401100.900</Zsz_ObjectAcctSub_OSBOW_ID3>
<SumBegBalance>-20</SumBegBalance>
<SumDebitPeriod>10</SumDebitPeriod>
<SumCreditPeriod>-5</SumCreditPeriod>
<SumEndBalance>-15</SumEndBalance>
</G_L_By_Object_Account___Localization_S10>
<G_L_By_Object_Account___Localization_S10>
<Zsz_ObjectAcctSub_OSBOW_ID3>401100.900</Zsz_ObjectAcctSub_OSBOW_ID3>
<SumBegBalance>100</SumBegBalance>
<SumDebitPeriod>10</SumDebitPeriod>
<SumCreditPeriod>-5</SumCreditPeriod>
<SumEndBalance>105</SumEndBalance>
</G_L_By_Object_Account___Localization_S10>
<G_L_By_Object_Account___Localization_S10>
<Zsz_ObjectAcctSub_OSBOW_ID3>411100.900</Zsz_ObjectAcctSub_OSBOW_ID3>
<SumBegBalance>-30</SumBegBalance>
<SumDebitPeriod>5</SumDebitPeriod>
<SumCreditPeriod>-10</SumCreditPeriod>
<SumEndBalance>-35</SumEndBalance>
</G_L_By_Object_Account___Localization_S10>
<G_L_By_Object_Account___Localization_S10>
<Zsz_ObjectAcctSub_OSBOW_ID3>451100.900</Zsz_ObjectAcctSub_OSBOW_ID3>
<SumBegBalance>80</SumBegBalance>
<SumDebitPeriod>20</SumDebitPeriod>
<SumCreditPeriod>-10</SumCreditPeriod>
<SumEndBalance>90</SumEndBalance>
</G_L_By_Object_Account___Localization_S10>
</RLA760910>
the result will be:
<?xml version="1.0" encoding="utf-8"?>
<result>
<group type="401100.900">
<total-of-begbalance>80</total-of-begbalance>
</group>
<group type="411100.900">
<total-of-begbalance>-30</total-of-begbalance>
</group>
<group type="451100.900">
<total-of-begbalance>80</total-of-begbalance>
</group>
</result>
Note that your expressions using #Zsz_ObjectAcctSub_OSBOW_ID3 fail because Zsz_ObjectAcctSub_OSBOW_ID3 is an element, not an attribute.

Related

I tried to remove specific element if its output is empty in XSLT

I am trying to remove Error Description element if it contains empty value using xslt. i tried lot of options but it does not work.
For example if inside Acknowledgement all the element get null then output get empty acknowledgement so I want remove acknowledgement element empty tag.
below is xml and xslt
<?xml version="1.0" encoding="UTF-8" ?>
<updateDocumentStatusResponse xmlns="http://xmlns.be/CommgrService_Message/v001">
<Acknowledgement>
<Result>SUCCESS</Result>
<ErrorCode>ErrorCode1375</ErrorCode>
<ErrorDescription></ErrorDescription>
</Acknowledgement>
</updateDocumentStatusResponse>
XSLT :
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:ns1="http://xmlns.be/CSM/v001" xmlns:mhdr="http://www.oracle.com/XSL/Transform/java/oracle.tip.mediator.service.common.functions.MediatorExtnFunction" xmlns:oraext="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.ExtFunc" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xp20="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.Xpath20" xmlns:xref="http://www.oracle.com/XSL/Transform/java/oracle.tip.xref.xpath.XRefXPathFunctions" xmlns:socket="http://www.oracle.com/XSL/Transform/java/oracle.tip.adapter.socket.ProtocolTranslator" xmlns:oracle-xsl-mapper="http://www.oracle.com/xsl/mapper/schemas" xmlns:dvm="http://www.oracle.com/XSL/Transform/java/oracle.tip.dvm.LookupValue" xmlns:oraxsl="http://www.oracle.com/XSL/Transform/java" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns0="http://xmlns.be/CommgrService_Message/v001" exclude-result-prefixes=" xsd oracle-xsl-mapper xsi xsl ns1 ns0 mhdr oraext xp20 xref socket dvm oraxsl"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
<oracle-xsl-mapper:schema>
<oracle-xsl-mapper:mapSources>
<oracle-xsl-mapper:source type="WSDL">
<oracle-xsl-mapper:schema location="../WSDLs/CommgrService_v001.wsdl"/>
<oracle-xsl-mapper:rootElement name="updateDocumentStatusResponse" namespace="http://xmlns.be/CommgrService_Message/v001"/>
</oracle-xsl-mapper:source>
</oracle-xsl-mapper:mapSources>
</oracle-xsl-mapper:schema>
<!--User Editing allowed BELOW this line - DO NOT DELETE THIS LINE-->
<xsl:template match="/">
<ns1:Output>
<ns1:CommunicationResponse>
<ns1:Acknowledgement>
<ns1:Result>
<xsl:value-of select="/ns0:updateDocumentStatusResponse/ns0:Acknowledgement/ns0:Result"/>
</ns1:Result>
<ns1:ErrorCode>
<xsl:value-of select="/ns0:updateDocumentStatusResponse/ns0:Acknowledgement/ns0:ErrorCode"/>
</ns1:ErrorCode>
<ns1:ErrorDescription>
<xsl:value-of select="/ns0:updateDocumentStatusResponse/ns0:Acknowledgement/ns0:ErrorDescription"/>
</ns1:ErrorDescription>
</ns1:Acknowledgement>
</ns1:CommunicationResponse>
</ns1:Output>
</xsl:template>
</xsl:stylesheet>
how can i achieve this?
I think this can be done if you're not thinking something big:
<xsl:if test="normalize-space(/ns0:updateDocumentStatusResponse/ns0:Acknowledgement/ns0:ErrorDescription) != ''">
<ns1:ErrorDescription>
<xsl:value-of select="/ns0:updateDocumentStatusResponse/ns0:Acknowledgement/ns0:ErrorDescription"/>
</ns1:ErrorDescription>
</xsl:if>
Edit:
One way to achieve this using extension function like exsl:node-set or msxsl:node-set to be able to further process a result tree fragment created in another template:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:ns1="http://xmlns.be/CSM/v001" xmlns:mhdr="http://www.oracle.com/XSL/Transform/java/oracle.tip.mediator.service.common.functions.MediatorExtnFunction" xmlns:oraext="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.ExtFunc" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xp20="http://www.oracle.com/XSL/Transform/java/oracle.tip.pc.services.functions.Xpath20" xmlns:xref="http://www.oracle.com/XSL/Transform/java/oracle.tip.xref.xpath.XRefXPathFunctions" xmlns:socket="http://www.oracle.com/XSL/Transform/java/oracle.tip.adapter.socket.ProtocolTranslator" xmlns:oracle-xsl-mapper="http://www.oracle.com/xsl/mapper/schemas" xmlns:dvm="http://www.oracle.com/XSL/Transform/java/oracle.tip.dvm.LookupValue" xmlns:oraxsl="http://www.oracle.com/XSL/Transform/java" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns0="http://xmlns.be/CommgrService_Message/v001" exclude-result-prefixes=" xsd oracle-xsl-mapper xsi xsl ns1 ns0 mhdr oraext xp20 xref socket dvm oraxsl"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
<oracle-xsl-mapper:schema>
<oracle-xsl-mapper:mapSources>
<oracle-xsl-mapper:source type="WSDL">
<oracle-xsl-mapper:schema location="../WSDLs/CommgrService_v001.wsdl" />
<oracle-xsl-mapper:rootElement name="updateDocumentStatusResponse" namespace="http://xmlns.be/CommgrService_Message/v001" />
</oracle-xsl-mapper:source>
</oracle-xsl-mapper:mapSources>
</oracle-xsl-mapper:schema>
<!--User Editing allowed BELOW this line - DO NOT DELETE THIS LINE -->
<xsl:template match="/">
<xsl:variable name="result">
<ns1:Output>
<ns1:CommunicationResponse>
<ns1:Acknowledgement>
<ns1:Result>
<xsl:value-of select="/ns0:updateDocumentStatusResponse/ns0:Acknowledgement/ns0:Result" />
</ns1:Result>
<ns1:ErrorCode>
<xsl:value-of select="/ns0:updateDocumentStatusResponse/ns0:Acknowledgement/ns0:ErrorCode" />
</ns1:ErrorCode>
<ns1:ErrorDescription>
<xsl:value-of select="/ns0:updateDocumentStatusResponse/ns0:Acknowledgement/ns0:ErrorDescription" />
</ns1:ErrorDescription>
</ns1:Acknowledgement>
</ns1:CommunicationResponse>
</ns1:Output>
</xsl:variable>
<xsl:apply-templates select="exsl:node-set($result)/*" mode="step2" />
</xsl:template>
<xsl:template match="*[not(normalize-space())]" mode="step2" />
<xsl:template match="#* | node()" mode="step2">
<xsl:copy>
<xsl:apply-templates select="#* | node()" mode="step2" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
http://xsltransform.net/93wkLHW
If you take a top-down aproach with literal result elements you are always going to get that element in the output. Your only choice then is to chain two transformations or use a two pass transformation.
The XPath expression to know whether the current node is empty (true) or not (false) is:
"not(node())"
For example, this input document
<?xml version="1.0" encoding="UTF-8" ?>
<updateDocumentStatusResponse xmlns="http://xmlns.be/CommgrService_Message/v001">
<Acknowledgement>
<Result>SUCCESS</Result>
<ErrorCode>ErrorCode1375</ErrorCode>
<ErrorDescription></ErrorDescription>
</Acknowledgement>
</updateDocumentStatusResponse>
With this transformation
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements ="*"/>
<xsl:output indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*[not(node())]"/>
</xsl:stylesheet>
Output
<updateDocumentStatusResponse xmlns="http://xmlns.be/CommgrService_Message/v001">
<Acknowledgement>
<Result>SUCCESS</Result>
<ErrorCode>ErrorCode1375</ErrorCode>
</Acknowledgement>
</updateDocumentStatusResponse>
Edit
The previus stylesheet is general. If you want to target specific elements, you need to match those elements with the pattern in the template. Example:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements ="*"/>
<xsl:output indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ErrorDescription[not(node())]"/>
</xsl:stylesheet>

Is there a way to replace the for-each with apply-templates in an XSLT Transform?

Environment: XSLT 1.0
The transform will take each element in partOne section and lookup #field attribute in partTwo section using #find attribute and then output #value attribute.
I'm using a for-each loop and was wondering if apply-templates could work?
xml
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="file.xslt"?>
<xml>
<partOne>
<target field="hello"/>
<target field="world"/>
</partOne>
<partTwo>
<number input="2" find="hello" value="valone" />
<number input="2" find="world" value="valtwo" />
<number input="2" find="hello" value="valthree" />
<number input="2" find="world" value="valfour" />
</partTwo>
</xml>
xsl
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="text"/>
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="/xml/partOne/target">
,<xsl:value-of select="#field"/>
<xsl:for-each select="/xml/partTwo/number[#find=current()/#field]">
,<xsl:value-of select="#value"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Output:
,hello
,valone
,valthree
,world
,valtwo
,valfour
Well, it seems straight-forward to change
<xsl:for-each select="/xml/partTwo/number[#find=current()/#field]">
,<xsl:value-of select="#value"/>
</xsl:for-each>
to
<xsl:apply-templates select="/xml/partTwo/number[#find=current()/#field]"/>
with a template
<xsl:template match="partTwo/number">
,<xsl:value-of select="#value"/>
</xsl:template>
As your root template so far processes all elements you need to change it to
<xsl:template match="/">
<xsl:apply-templates select="xml/partOne"/>
</xsl:template>
to avoid processing the partTwo element(s) twice.
For the cross-reference you might want to use a key in both versions:
<xsl:key name="ref" match="partTwo/number" use="#find"/>
and then select="key('ref', #field)" instead of select="/xml/partTwo/number[#find=current()/#field]" for the apply-templates or for-each.

change of xml structure using xslt

I want to convert the following source xml structure to the target xml structure using xslt transformation. I am mot able to convert the following source xml to target xml using xslt. Please help us in coneverting this.
Source XML
<XxhrPiEmpcompOutIntCollection>
<XxhrPiEmpcompOutInt>
<employeeNumber>
200000562
</employeeNumber>
<competencyName>
Comp1
</competencyName>
<proficiencyLevel>
Prof1
</proficiencyLevel>
<compDateTo>
16-NOV-12
</compDateTo>
</XxhrPiEmpcompOutInt>
<XxhrPiEmpcompOutInt>
<employeeNumber>
200000562
</employeeNumber>
<competencyName>
Comp2
</competencyName>
<proficiencyLevel>
Prof2
</proficiencyLevel>
<compDateTo>
16-NOV-12
</compDateTo>
</XxhrPiEmpcompOutInt>
</XxhrPiEmpcompOutIntCollection>
Target xml
<EmployeeCompetencyRequest>
<EmployeeNumber>200000562</EmployeeNumber>
<Competencies>
<Competency>
<Name>Comp1</Name>
<ProficiencyLevel>Prof1</ProficiencyLevel>
<EndDate>16-NOV-12</EndDate>
</Competency>
<Competency>
<Name>Comp2</Name>
<ProficiencyLevel>Prof2</ProficiencyLevel>
<EndDate>16-NOV-12</EndDate>
</Competency>
</Competencies>
</<EmployeeCompetencyRequest>
Some hint :
<EmployeeCompetencyRequest>
template match /XxhrPiEmpcompOutIntCollection
for-each-group XxhrPiEmpcompOutInt group by employeeNumber
<EmployeeNumber> value-of current-group-key </EmployeeNumber>
<Competencies>
for-each current-group
<Competency>
value-of name
value-of proficiencyLevel
</competency>
/for-each
</Competencies>
/for-each-group
<EmployeeCompetencyRequest>
Hope you can finish it.
You can group users with for-each-group:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:output indent="yes"/>
<xsl:template match="/">
<EmployeeCompetencyRequest>
<xsl:for-each-group select="//XxhrPiEmpcompOutInt" group-by="employeeNumber">
<Name><xsl:value-of select="current-grouping-key()"/></Name>
<Competencies>
<xsl:for-each select="current-group()">
<Competency>
<Name><xsl:value-of select="competencyName"/></Name>
<ProfiencyLevel><xsl:value-of select="profiencyLevel"/></ProfiencyLevel>
<EndDate><xsl:value-of select="compDateTo"/></EndDate>
</Competency>
</xsl:for-each>
</Competencies>
</xsl:for-each-group>
</EmployeeCompetencyRequest>
</xsl:template>
Salut,
For XSLT 1.0 you must group widht xsl:key:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="groups" match="/XxhrPiEmpcompOutIntCollection/XxhrPiEmpcompOutInt" use="employeeNumber" />
<xsl:template match="/">
<EmployeeCompetencyRequest>
<xsl:apply-templates select="//XxhrPiEmpcompOutInt[generate-id() = generate-id(key('groups', employeeNumber)[1])]"/>
</EmployeeCompetencyRequest>
</xsl:template>
<xsl:template match="XxhrPiEmpcompOutInt">
<Name><xsl:value-of select="employeeNumber"/></Name>
<Competencies>
<xsl:for-each select="key('groups', employeeNumber)">
<Competency>
<Name><xsl:value-of select="competencyName"/></Name>
<ProfiencyLevel><xsl:value-of select="proficiencyLevel"/></ProfiencyLevel>
<EndDate><xsl:value-of select="compDateTo"/></EndDate>
</Competency>
</xsl:for-each>
</Competencies>
</xsl:template>
</xsl:stylesheet>
I can't test it with Oracle ...

attribute value using msxml from xml

I have the following XML
<?xml version="1.0" encoding="ISO-8859-1" ?>
- <DEVICEMESSAGES>
<VERSION xml="1" checksum="" revision="0" envision="33050000" device="" />
<HEADER id1="0001" id2="0001" content="Nasher[<messageid>]: <!payload>" />
<MESSAGE level="7" parse="1" parsedefvalue="1" tableid="15" id1="24682" id2="24682" eventcategory="1003010000" content="Access to <webpage> was blocked due to its category (<info> by <hostname>)" />
</DEVICEMESSAGES>
I am using the following xslt
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="DEVICEMESSAGES">
<xsl:value-of select="#id2"/>,<xsl:text/>
<xsl:value-of select="#content"/>,<xsl:text/>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
when i use MSXML i just get ,, whereas i want to have something like
id2, content
0001 , Nasher[<messageid>]: <!payload>"
The DEVICEMESSAGES element doesn't have attributes at all.
Change:
<xsl:template match="DEVICEMESSAGES">
to:
<xsl:template match="DEVICEMESSAGES/HEADER">

XSLT node Traversal

Here is a snip-it of the XML:
<?xml version="1.0" encoding="iso-8859-1" ?>
<NetworkAppliance id="S123456">
<Group id="9">
<Probe id="1">
<Value>74.7</Value>
</Probe>
</NetworkAppliance>
I want to get the single point value of 74.7. There are many groups with unique ID's and many Probes under that group with unique ID's each with values.
I am looking for example XSLT code that can get me this one value. Here is what i have that does not work:
<?xml version="1.0" ?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" version="3.2" />
<xsl:template match="NetworkAppliance">
<xsl:apply-templates select="Group[#id='9']"/>
</xsl:template>
<xsl:template match="Group">
Temp: <xsl:value-of select="Probe[#id='1']/Value"/>
<br/>
</xsl:template>
</xsl:stylesheet>
Here is what worked for me in the end:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by XMLSpy® -->
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<xsl:for-each select="NetworkAppliance/Group[#id=9]/Probe[#id=1]">
Value: <xsl:value-of select="Value" />
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Don't forget that you can do select several levels at once. Fixing your XML to:
<?xml version="1.0" encoding="iso-8859-1" ?>
<NetworkAppliance id="S123456">
<Group id="9">
<Probe id="1">
<Value>74.7</Value>
</Probe>
</Group>
</NetworkAppliance>
and using this stylesheet:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" version="3.2" />
<xsl:template match="/">
Temp: <xsl:value-of select="//Group[#id='9']/Probe[#id='1']/Value"/>
<br/>
</xsl:template>
</xsl:stylesheet>
we can pick out that one item you're interested in.
Points to note:
The // part of the expression means that the search for Group nodes takes place throughout the whole tree, finding Group nodes at whatever depth they're at.
The [#id='9'] part selects those Group nodes with id of 9
The Probe[#id='1'] part immediately after that selects those children of the Group nodes it found where the id is 1, and so on.
<xsl:value-of select="/NetworkAppliance/Group[#id=9]/Probe[#id=1]/Value"/>
XSLT is just one of the tools in the box, and nothing without XPath.
the xpath for value of a node is /node/text()
So
<xsl:value-of select="Probe[#id='1']/text()"/>