Count the child Node - xslt-2.0

I have below payload ,where I have to count number of child elements under <Document>.
For example:
<Document>
<Class>D</Class>`enter code here`
<ClassDescription>Drawings</ClassDescription>
<ClientDocumentNumber>12345</ClientDocumentNumber>
<Document>
The count will be 3.
The Payload is as below. Check this code.
<?xml version="1.0" encoding="UTF-8"?>
<InputVariable>
<part name="payload">
<ProjectMessage>
<ConversationId>E53252F709653493E0401E0A13916A2E</ConversationId>
<SourceApplicationId>Convero</SourceApplicationId>
<Operation>INS DOC</Operation>
<ModifiedByUserEmail>daviD.Woo#xyz.com</ModifiedByUserEmail>
<Project>
<Id>100020</Id>
<DocumentList>
<Document>
<Class>D</Class>
<ClassDescription>Drawings</ClassDescription>
<ClientDocumentNumber>12345</ClientDocumentNumber>
<ClientRevisionNumber>2.0</ClientRevisionNumber>
<Discipline>141</Discipline>
<DisciplineDescription>ACN</DisciplineDescription>
<Facility>24</Facility>
<Number>100020-24-140-SKT-0002</Number>
<OSROriginator>086238</OSROriginator>
<Revision>2.0</Revision>
<RevisionDate>2013-02-11T00:00:00Z</RevisionDate>
<Status>A</Status>
<StatusDescription>Active</StatusDescription>
<SupplierDocumentNumber>523570.000</SupplierDocumentNumber>
<SupplierRevisionNumber>CCC</SupplierRevisionNumber>
<Title>Test for FileNet</Title>
<Type>NA</Type>
<TypeDescription>NA</TypeDescription>
</Document>
</DocumentList>
</Project>
</ProjectMessage>
</part>
</InputVariable>

<xsl:template match="Document">
<xsl:value-of select="count(*)"/>
</xsl:template>
is a template matching Document elements and counting the child elements.

Related

How to compare a single value to an array using XSLT

I want to compare a single value if it's existing to an array. I have an XML input file:
<wd:Report_Entry
xmlns:wd="urn:com.workday.report/CRI_-_INTSG031_CM_011_-_PUBBS_HSA_Customer_Invoice">
<wd:CFI_ARI_PUBBS_HSA_group>
<wd:pubbsType>1</wd:pubbsType>
<wd:pubbsService>A+</wd:pubbsService>
<wd:validFrom>2019-08-01</wd:validFrom>
<wd:validTo>2100-01-01</wd:validTo>
<wd:CF_FD_PUBBS_HSA_Valid_From_Date>2019-08-01</wd:CF_FD_PUBBS_HSA_Valid_From_Date>
<wd:CF_FD_PUBBS_HSA_Valid_To_Date>2100-01-01</wd:CF_FD_PUBBS_HSA_Valid_To_Date>
</wd:CFI_ARI_PUBBS_HSA_group>
<wd:CFI_ARI_PUBBS_HSA_group>
<wd:pubbsType>1</wd:pubbsType>
<wd:pubbsService>A-</wd:pubbsService>
<wd:validFrom>2019-08-01</wd:validFrom>
<wd:validTo>2100-01-01</wd:validTo>
<wd:CF_FD_PUBBS_HSA_Valid_From_Date>2019-08-01</wd:CF_FD_PUBBS_HSA_Valid_From_Date>
<wd:CF_FD_PUBBS_HSA_Valid_To_Date>2100-01-01</wd:CF_FD_PUBBS_HSA_Valid_To_Date>
</wd:CFI_ARI_PUBBS_HSA_group>
<wd:CFI_ARI_PUBBS_HSA_group>
<wd:pubbsType>FMDAUTOPSY</wd:pubbsType>
<wd:pubbsService>FMDAUTOPSY</wd:pubbsService>
<wd:validFrom>2020-02-02</wd:validFrom>
<wd:validTo>2020-02-01</wd:validTo>
<wd:CF_FD_PUBBS_HSA_Valid_From_Date>2020-02-01</wd:CF_FD_PUBBS_HSA_Valid_From_Date>
<wd:CF_FD_PUBBS_HSA_Valid_To_Date>2100-01-01</wd:CF_FD_PUBBS_HSA_Valid_To_Date>
</wd:CFI_ARI_PUBBS_HSA_group>
<wd:CFI_ARI_PUBBS_HSA_group>
<wd:pubbsType>FMDBODYSTOR</wd:pubbsType>
<wd:pubbsService>FMDBODYSTOR</wd:pubbsService>
<wd:validFrom>2020-01-01</wd:validFrom>
<wd:validTo>2020-01-31</wd:validTo>
<wd:CF_FD_PUBBS_HSA_Valid_From_Date>2020-01-01</wd:CF_FD_PUBBS_HSA_Valid_From_Date>
<wd:CF_FD_PUBBS_HSA_Valid_To_Date>2020-01-31</wd:CF_FD_PUBBS_HSA_Valid_To_Date>
</wd:CFI_ARI_PUBBS_HSA_group>
<wd:Customer_Invoice_Lines_group>
<wd:referenceID>CUSTOMER_INVOICE_LINE-6-46</wd:referenceID>
<wd:Unit_Cost>0</wd:Unit_Cost>
<wd:Quantity>0</wd:Quantity>
<wd:Calculated_Tax_Amount>0</wd:Calculated_Tax_Amount>
<wd:CFI_AC_Merchandise_Amount>100</wd:CFI_AC_Merchandise_Amount>
<wd:Line_Item_Description>LINE ITEM DESC</wd:Line_Item_Description>
<wd:Line_Memo>LINE MEMO</wd:Line_Memo>
<wd:Transaction_Tax_Amount>0</wd:Transaction_Tax_Amount>
<wd:CFI_LRV_Sales_Item_Reference_ID>FMDAUTOPSY</wd:CFI_LRV_Sales_Item_Reference_ID>
</wd:Customer_Invoice_Lines_group>
<wd:CFI_FD_PUBBS_HSA_Current_Date>2020-02-16</wd:CFI_FD_PUBBS_HSA_Current_Date>
</wd:Report_Entry>
I want to know if the wd:CFI_LRV_Sales_Item_Reference_ID value is equal to wd:Customer_Invoice_Lines_group/wd:CFI_ARI_PUBBS_HSA_group/wd:pubbsService and wd:CFI_FD_PUBBS_HSA_Current_Date is greater than wd:CF_FD_PUBBS_HSA_Valid_To_Date and then just return a string value true if there is. I have a code like this but this doesn't work because I'm comparing a value to an object that has multiple values. Not sure how to do compare single value to an array using xslt 2 or 3.. Appreciate the help.
<?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" xmlns:mf="http://example.com/mf"
exclude-result-prefixes="#all" version="3.0"
xmlns:wd="urn:com.workday.report/CRI_-_INTSG031_CM_011_-_PUBBS_HSA_Customer_Invoice"
xmlns:d9="urn:this-stylesheet">
<xsl:output method="xml"/>
<xsl:template match="/">
<PUBBS>
<xsl:for-each select="wd:Report_Entry/wd:Customer_Invoice_Lines_group">
<xsl:if test="wd:CFI_LRV_Sales_Item_Reference_ID != ''">
<xsl:for-each select="../wd:CFI_ARI_PUBBS_HSA_group">
<xsl:if test="../wd:CFI_ARI_PUBBS_HSA_group/wd:pubbsService != ''
and wd:CFI_LRV_Sales_Item_Reference_ID = ../wd:CFI_ARI_PUBBS_HSA_group/wd:pubbsService
and xs:date(../wd:CFI_FD_PUBBS_HSA_Current_Date) > xs:date(../wd:CFI_ARI_PUBBS_HSA_group/wd:CF_FD_PUBBS_HSA_Valid_To_Date)
">
<HASINVALIDSALESITEM>
<xsl:value-of select="'true'"/>
</HASINVALIDSALESITEM>
</xsl:if>
</xsl:for-each>
</xsl:if>
</xsl:for-each>
</PUBBS>
</xsl:template>
</xsl:stylesheet>
I have tried to simplify the code by using xpath-default-namespace and by using templates; I have also assumed the two values you want to compare the two details of the various CFI_ARI_PUBBS_HSA_group to only exist once in the input document:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xpath-default-namespace="urn:com.workday.report/CRI_-_INTSG031_CM_011_-_PUBBS_HSA_Customer_Invoice"
exclude-result-prefixes="#all"
version="3.0">
<xsl:output method="xml" indent="yes"/>
<xsl:mode on-no-match="shallow-skip"/>
<xsl:template match="/*">
<PUBBS>
<xsl:apply-templates select="CFI_ARI_PUBBS_HSA_group"/>
</PUBBS>
</xsl:template>
<xsl:template match="CFI_ARI_PUBBS_HSA_group[xs:date(//CFI_FD_PUBBS_HSA_Current_Date) > xs:date(CF_FD_PUBBS_HSA_Valid_To_Date)
and
//CFI_LRV_Sales_Item_Reference_ID = pubbsService]">
<HASINVALIDSALESITEM>true</HASINVALIDSALESITEM>
</xsl:template>
</xsl:stylesheet>
At https://xsltfiddle.liberty-development.net/jz1Q1ym that gives an empty <PUBBS/>, which seems the right result as the only CFI_ARI_PUBBS_HSA_group with pubbsService having the value FMDAUTOPSY has a CF_FD_PUBBS_HSA_Valid_To_Date of 2100-01-01 and the CFI_FD_PUBBS_HSA_Current_Date with the value 2020-02-16 is not greater than that.
It is not quite clear whether you want a single output of HASINVALIDSALESITEM even if there are several but the code could obviously adapted.

recursive call in nested xml fails

I want to recursively call on element vrijeInhoudGroep, but the node test in the choose clause is not performed. Instead, the second test on element vrijeInhoudElement is successful. Everything I have applied does not work. Can anyone give me a backing?
My xml input:
<?xml version="1.0"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="http://services" xmlns:v11="http://services11" xmlns:v12="http://services12">
<soapenv:Header/>
<soapenv:Body>
<v1:creeerDocumentRequest>
<v11:documentInhoud>
<v12:vrijeInhoudGroep type="FirstGroep">
<v12:vrijInhoudGroep type="GenesteGroep_1">
<v12:vrijeInhoudElement>
<v12:label>Label1</v12:label>
<v12:waarde>waard1</v12:waarde>
<v12:datatype>tekst1</v12:datatype>
</v12:vrijeInhoudElement>
<v12:vrijeInhoudElement>
<v12:label>Label2</v12:label>
<v12:waarde>waard2</v12:waarde>
<v12:datatype>tekst2</v12:datatype>
</v12:vrijeInhoudElement>
</v12:vrijInhoudGroep>
<v12:vrijInhoudGroep type="GenesteGroep_2">
<v12:vrijeInhoudElement>
<v12:label>Label3</v12:label>
<v12:waarde>waard3</v12:waarde>
<v12:datatype>tekst3</v12:datatype>
</v12:vrijeInhoudElement>
</v12:vrijInhoudGroep>
<v12:vrijeInhoudElement>
<v12:label>Label4</v12:label>
<v12:waarde>waard4</v12:waarde>
<v12:datatype>tekst4</v12:datatype>
</v12:vrijeInhoudElement>
<v12:vrijeInhoudElement>
<v12:label>Label5</v12:label>
<v12:waarde>waard5</v12:waarde>
<v12:datatype>tekst5</v12:datatype>
</v12:vrijeInhoudElement>
</v12:vrijeInhoudGroep>
</v11:documentInhoud>
</v1:creeerDocumentRequest>
</soapenv:Body>
</soapenv:Envelope>
My xml output:
<?xml version="1.0" encoding="UTF-8"?>
<vrijeInhoudGroep type="documentInhoud">
<vrijeInhoudGroep>v12:vrijeInhoudGroep</vrijeInhoudGroep>
<ELLEMENT/>
<mywrapper>
<v12:label xmlns:soapenv="http://s...">Label4</v12:label>
<v12:waarde xmlns:soapenv="http://s..." >waard4</v12:waarde>
<v12:datatype xmlns:soapenv="http://s..." >tekst4</v12:datatype>
</mywrapper>
<mywrapper>
<v12:label xmlns:soapenv="http://s...." >Label5</v12:label>
<v12:waarde xmlns:soapenv="http://s..." >waard5</v12:waarde>
<v12:datatype xmlns:soapenv="http://s...">tekst5</v12:datatype>
</mywrapper>
</vrijeInhoudGroep>
My xslt:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:v11="http://services11" xmlns:v12="http://services12" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:v1="http://services"
version="2.0"
exclude-result-prefixes="v11 v12 v1 xsi xs">
<xsl:output method="xml" indent="no"/>
<xsl:template match="/">
<xsl:apply-templates select="//v1:creeerDocumentRequest"/>
</xsl:template>
<xsl:template match="v1:creeerDocumentRequest">
<vrijeInhoudGroep type="documentInhoud">
<xsl:apply-templates select="v11:documentInhoud"/>
</vrijeInhoudGroep>
</xsl:template>
<xsl:template match="v11:documentInhoud">
<xsl:apply-templates select="v12:vrijeInhoudGroep"/>
</xsl:template>
<xsl:template match="v12:vrijeInhoudGroep[#type]">
<vrijeInhoudGroep>
<xsl:value-of select="name()"/>
</vrijeInhoudGroep>
<xsl:choose>
<xsl:when test="v12:vrijeInhoudGroep">
<!-- HERE I TRY A RECURSIVE CALL, BUT THIS TEST DOES'T WORK -->
<xsl:apply-templates select="v12:vrijeInhoudGroep"/>
</xsl:when>
<xsl:when test="v12:vrijeInhoudElement">
<!-- INSTEAD IT COMES HERE TO PROCES THE vrijeInhoudElement -->
<ELLEMENT/>
<xsl:apply-templates select="v12:vrijeInhoudElement"/>
</xsl:when>
<xsl:otherwise><NOPE/></xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="v12:vrijeInhoudElement">
<mywrapper>
<xsl:copy-of select="node()"/>
</mywrapper>
</xsl:template>
</xsl:stylesheet>
Target xml should be something like this:
<...>
<vrijeInhoudGroep type="EerstGroep">
<vrijeInhoudGroep type="GenesteGroep_1">
<vrijeInhoudElement naam="Label1 format="tekst1">waard1</vrijeInhoudElement>
</vrijeInhoudGroep>
<vrijeInhoudGroep type="GenesteGroep_2">
<vrijeInhoudElement naam="Label2 format="tekst2">waard2</vrijeInhoudElement>
<vrijeInhoudElement naam="Label3 format="tekst3">waard3</vrijeInhoudElement>
</vrijeInhoudGroep>
<vrijeInhoudElement naam="Label3 format="tekst3">waard3</vrijeInhoudElement>
<vrijeInhoudElement naam="Label4 format="tekst4">waard4</vrijeInhoudElement>
</vrijeInhoudGroep>
</...>
What should I do to make this recursive call work properly?

SaxonApiException: The context item for axis step ./CLIENT is absent

I am trying to convert and XML to an XML using XSLT 2.0 in saxon/java. I am using a sample XML I found on stack overflow thread "Applying Muenchian grouping for a simple XML with XSLT"
However I am getting an error : XPDY0002: The context item for axis step ./CLIENT is absent.
My test XSL:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:output omit-xml-declaration="no" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="CLIENTS" name="main">
<CLIENTS>
<xsl:for-each-group select="CLIENT" group-by="NAME">
<xsl:comment><xsl:value-of select="current-grouping-key()"/> </xsl:comment>
<CLIENT>
<xsl:sequence select="NAME" />
<xsl:for-each select="current-group()">
<ACCOUNT>
<xsl:sequence select="*[not(self::NAME)]" />
</ACCOUNT>
</xsl:for-each>
</CLIENT>
</xsl:for-each-group>
</CLIENTS>
</xsl:template>
</xsl:stylesheet>
My Test XML:
<CLIENTS>
<CLIENT>
<NAME>John</NAME>
<ACCOUNT_NUMBER>1424763562761</ACCOUNT_NUMBER>
<LAST_USED>2012-10-03</LAST_USED>
<AMOUNT>5000</AMOUNT>
</CLIENT>
<CLIENT>
<NAME>John</NAME>
<ACCOUNT_NUMBER>543667543732</ACCOUNT_NUMBER>
<LAST_USED>2012-10-02</LAST_USED>
<AMOUNT>10000</AMOUNT>
</CLIENT>
</CLIENTS>
My Java ( which works with other transforms) :
void xmlXSLTParser(){
String xslFile = commonPath + "/xslt/inputPointCSVTOXML_style2.xsl";
String inputFile = "file:///" + commonPath + pointWorkFile;
String outputFile = commonPath + pointWorkFile + ".final";
try {
Processor proc = new Processor(false);
XsltCompiler comp = proc.newXsltCompiler();
XsltExecutable exp = comp.compile(new StreamSource(new File(xslFile)));
Serializer out = new Serializer();
out.setOutputProperty(Serializer.Property.METHOD, "xml");
out.setOutputProperty(Serializer.Property.INDENT, "yes");
out.setOutputFile(new File(outputFile));
XsltTransformer trans = exp.load();
trans.setInitialTemplate(new QName("main"));
//trans.setParameter(new QName("url-of-csv"),new XdmAtomicValue(inputFile));
trans.setDestination(out);
trans.transform();
System.out.println("Output written to text file");
} catch (SaxonApiException e) {
println("XSLT Error :" + e );
}
}
}
My Error in detail:
Error at char 6 in xsl:for-each-group/#select on line 10 column 59 of inputPointCSVTOXML_style2.xsl:
XPDY0002: The context item for axis step ./CLIENT is absent
XSLT Error :net.sf.saxon.s9api.SaxonApiException: The context item for axis step ./CLIENT is absent
Your Java code does not set any context item, instead it sets an initial template. So you will need to make sure you provide the input XML as the context item to the XsltTransformer, using http://saxonica.com/html/documentation/javadoc/net/sf/saxon/s9api/XsltTransformer.html#setInitialContextNode(net.sf.saxon.s9api.XdmNode) or as a Source, using http://saxonica.com/html/documentation/javadoc/net/sf/saxon/s9api/XsltTransformer.html#setSource(javax.xml.transform.Source).
So instead of trans.setInitialTemplate(new QName("main")); use trans.setSource(new StreamSource(inputFile));.

Nokogiri get xpath from Nokogiri::XML::Element

How to get xpath for rc an element returned by search
f=File.open('/media/cc.xml')
doc = Nokogiri::XML f
rc = doc.search('realmCode')
[#<Nokogiri::XML::Element:0x15a4d714 name="realmCode" namespace=#<Nokogiri::XML::Namespace:0x15a4dafc href="urn:hl7-org:v3"> attributes=[#<Nokogiri::XML::Attr:0x15a4d5c0 name="code" value="US">]>]
Is there a way to extract xpath from rc ?
updated with xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="/ccda.xsl"?>
<ClinicalDocument xmlns:sdtc="urn:hl7-org:sdtc" xmlns:vocdo="urn:hl7-org:v3/voc" xmlns="urn:hl7-org:v3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mif="urn:hl7-org:v3/mif">
<realmCode code="US"/>
<typeId root="2.16.840.1.113883.1.3" extension="POCD_HD000040"/>
<templateId root="2.16.840.1.113883.10.20.22.1.1"/>
<templateId root="2.16.840.1.113883.10.20.22.1.2"/>
<id root="2.16.840.1.113883.19.5.99999.1" extension="Test CCDA"/>
<code codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC" code="34133-9" displayName="Summarization of Episode Note"/>
<title>Continuity of Care Document (C-CDA)</title>
<effectiveTime value="20130809043133+0000"/>
<confidentialityCode codeSystem="2.16.840.1.113883.5.25" codeSystemName="HL7 Confidentiality" code="N" displayName="Normal"/>
<languageCode code="en-US"/>
<recordTarget>
<patientRole>
<id root="2.16.840.1.113883.4.6" extension="1"/>
<id root="2.16.840.1.113883.4.1" extension="123-101-5230"/>
<addr use="HP">
<streetAddressLine>1357 Amber Drive</streetAddressLine>
<city nullFlavor="UNK"/>
<state nullFlavor="UNK"/>
<postalCode>97006</postalCode>
<country nullFlavor="UNK"/>
</addr>
<telecom value="3545345" use="HP"/>
<patient>
<name use="L">
<given qualifier="BR">test</given>
<family qualifier="CL">overall</family>
<prefix qualifier="IN">Mr</prefix>
</name>
<administrativeGenderCode codeSystem="2.16.840.1.113883.5.1" codeSystemName="HL7 AdministrativeGender" code="M" displayName="Male"/>
<birthTime value="19770429"/>
<raceCode codeSystem="2.16.840.1.113883.6.238" codeSystemName="Race and Ethnicity - CDC" code="2028-9" displayName="Asian"/>
<ethnicGroupCode codeSystem="2.16.840.1.113883.6.238" codeSystemName="Race and Ethnicity - CDC" code="2135-2" displayName="Hispanic or Latino"/>
<languageCommunication>
<languageCode code="eng"/>
<preferenceInd value="true"/>
</languageCommunication>
</patient>
</patientRole>
</recordTarget>
</ClinicalDocument>
rc is not an element-it's an array of matching elements:
results = rc.map do |node|
Nokogiri::CSS.xpath_for node.css_path
end
p results
Or, if you know there is only one matching element:
xpath = Nokogiri::CSS.xpath_for rc[0].css_path
Note that xpath_for returns an array, so you will need to extract the first element of the array:
xpath.first

libxml2 xml parsing issue

I have an xml file which i create myself.
<?xml version='1.0' encoding='utf-8' ?>
<Root>
<ChildElements>
<type name='xx' attr='false'>
<child id='1' regex='^[0-9]{11}$'>
<BBB>
<node1 name='aaa' regex='\w{5}'/>
<node2 name='bbb' regex='\w{3}'/>
</BBB>
</child>
<child>
.
.
.
</child>
</type>
</ChildElements>
</Root>
Something like this. I want to parse it to xml document object and iterate through its nodes, I'm using libxml2 for ios.
NSString *xmlPath = [[NSBundle mainBundle] pathForResource:#"xmlcontent" ofType:#"xml"];
NSData *xmlData = [NSData dataWithContentsOfFile:xmlPath];
NSString* xml = [[NSString alloc ] initWithData:xmlData encoding:NSUTF8StringEncoding];
int size=[xml lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
xmlDocPtr docptr=xmlParseMemory([xml UTF8String], size);
but in docptr object there is only one node, which is Root node, and when I try to get Root node child nodes it returns an empty node which name is #"text".
NSXMLParser easily parses the same XML, but I don't know how to create a document and iterate through nodes by using NSXMLParser.
maybe the error is, that your XML isn't valide:
<?xml version='1.0' encoding='utf-8' ?>
<Root>
<ChildElements>
<type name='xx' attr='false' />
<child id='1' regex='^[0-9]{11}$'>
<BBB>
<node1 name='aaa' regex='w{5}' />
<node2 name='bbb' regex='w{3}' />
</BBB>
</child>
</ChildElements>
</Root>
you can validate your XML with an online XML Validator

Resources