XSL: retrieve tag value - xslt

I have a special case because I need to check current value with preceding one.
In some cases the tag doesn't contain a value.
Sample XML:
<Row>
<Cell column="Contrat">
<Type>String</Type>
<Value>blabla</Value>
</Cell>
<Cell column="Dossier">
<Type>String</Type>
<Value>monitoring</Value>
</Cell>
<Cell column="DocVersion" />
<Cell column="CodeAffaire">
<Type>String</Type>
<Value>AF1302740</Value>
</Cell>
</Row>
In this case how can i detect that the tag DocVersion is without a value ?

Related

XSLT SELECT FOR-EACH element in list

I'm currently using Biztalk for mapping. I have a source order document that contains all parts that are being ordered. The destination document needs to contain only rows that contain a valid item (CELL/#C004) in Valid/Sku list. The valid SKU list is cached on the webserver and gets refreshed as necessary. Rather than hardcoding the list of valid parts in the map, I'm using a c# script to call the webservice and the valid sku data is mapped into a xslt variable. Is this a good approach?
The best solution I'm thinking of right now is iterating over all of the Row data <xslt:for-each select"/SOURCE/ROWS/ROW"> and then doing a check to see if the item is in the list of valid items. Is there a more efficent way to do this? something equivelant to select ROW/CELL[#Name='C004'] IN valid/sku list?
Source Document
<SOURCE>
...other nodes
<ROWS>
<ROW type="D" index="0 ">
<CELL name="C001" visible="X">
<VALUE>80710693</VALUE>
</CELL>
<CELL name="C002" visible="X">
<VALUE>10</VALUE>
</CELL>
<CELL name="C003" visible="X">
<VALUE>100100</VALUE>
</CELL>
<CELL name="C004" visible="X">
<VALUE>04001-17</VALUE>
</CELL>
<CELL name="C005" visible="X">
<VALUE decimals="3">100.000</VALUE>
</CELL>
</ROW>
<ROW type="D" index="0 ">
<CELL name="C001" visible="X">
<VALUE>80710693</VALUE>
</CELL>
<CELL name="C002" visible="X">
<VALUE>10</VALUE>
</CELL>
<CELL name="C003" visible="X">
<VALUE>100100</VALUE>
</CELL>
<CELL name="C004" visible="X">
<VALUE>05001-17</VALUE>
</CELL>
<CELL name="C005" visible="X">
<VALUE decimals="3">100.000</VALUE>
</CELL>
</ROW>
</ROWS>
</SOURCE>
list of valid values (about 1,500 values) from a webservice call.
<Valid>
<Sku>04001-17</<Sku>
<Sku>04002-17</<Sku>
<Sku>04003-17</<Sku>
</Valid>
XPath would be /SOURCE/ROWS/ROW[CELL[#name = 'C004']/VALUE = $skus/Valid/Sku] or with XSLT 2 or 3 I would define a key <xsl:key name="sku" match="Valid/Sku" use="."/> and use the path /SOURCE/ROWS/ROW[key('sku', CELL[#name = 'C004']/VALUE, $sku)].

Delete everything but dates Sublime Regex

I am matching all date formats in my file using the regex ([0-9]+)-+([0-9]+)-+([0-9]+) now how can i delete everything else but the matches? Thanks
Here is an example
<Data ss:Type="String">2017-03-10 15:57:34</Data>
</Cell>
<Cell>
<Data ss:Type="String">0</Data>
</Cell>
<Cell>
<Data ss:Type="String">Evelyne</Data>
</Cell>
<Cell>
<Data ss:Type="String">Evelyne</Data>
</Cell>
</Row>
<Row>
<Cell>
<Data ss:Type="String">170212</Data>
</Cell>
<Cell>
<Data ss:Type="String">everest</Data>
</Cell>
<Cell>
<Data ss:Type="String">everest</Data>
</Cell>
<Cell>
<Data ss:Type="String">sdfsd#gmail.com</Data>
</Cell>
<Cell>
<Data ss:Type="String"></Data>
</Cell>
<Cell>
<Data ss:Type="String">2017-04-29 10:21:09</Data>
I need to delete everything but the dates in Sublime using mac, thanks.
In the menu: Find -> Find
Enter your regex, then press FindAll
In the menu: Edit -> Copy
Delete contents of the file
In the menu: Edit -> Paste

xslt 2.0 multiple grouping

My Question: How can I apply double (or multiple) grouping?
Here is the source XML:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<root>
<row>
<Type>1</Type>
<WeaNr>100519</WeaNr>
</row>
<row>
<Type>2</Type>
<WeaNr>100519</WeaNr>
<ETADC_SKU>2007925</ETADC_SKU>
<CrossDock>N</CrossDock>
</row>
<row>
<Type>2</Type>
<WeaNr>100519</WeaNr>
<ETADC_SKU>12007925</ETADC_SKU>
<CrossDock>N</CrossDock>
</row>
<row>
<Type>2</Type>
<WeaNr>100519</WeaNr>
<ETADC_SKU>200792ww5</ETADC_SKU>
<CrossDock>Y</CrossDock>
</row>
<row>
<Type>1</Type>
<WeaNr>100520</WeaNr>
</row>
<row>
<Type>2</Type>
<WeaNr>100520</WeaNr>
<ETADC_SKU>2007925444</ETADC_SKU>
<CrossDock>N</CrossDock>
</row>
<row>
<Type>2</Type>
<WeaNr>100520</WeaNr>
<ETADC_SKU>2007925333</ETADC_SKU>
<CrossDock>Y</CrossDock>
</row>
<row>
<Type>2</Type>
<WeaNr>100520</WeaNr>
<ETADC_SKU>204445333</ETADC_SKU>
<CrossDock>Y</CrossDock>
</row>
</root>
I want use grouping by WeaNr and CrossDock
Expected results in this case are 4 groups:
1. WeaNr=100519 and CrossDock=N
2. WeaNr=100519 and CrossDock=Y
3. WeaNr=100520 and CrossDock=N
4. WeaNr=100520 and CrossDock=Y
Grouping just by one field, like WeaNr is easy:
<xsl:for-each-group select="row" group-by="WeaNr">
So how can I apply double (or multiple) grouping?
You would group-by some string that is a combination of the two, for example
<xsl:for-each-group select="row" group-by="concat(WeaNr, '|', CrossDock)">
or alternatively use two nested levels of for-each-group
<xsl:for-each-group select="row" group-by="WeaNr">
<xsl:for-each-group select="current-group()" group-by="CrossDock">
The difference between these two approaches is apparent if you use the position() function in the body of the for-each-group - in the concat case you'll get position values from 1 to 4, in the nested case you'll get 1, 2, 1, 2 (because the position() is determined by the nearest enclosing for-each-group). Similarly, last() will be 4 in the concat case and 2 in the nested case.

XML value to XML node conversion using XSLT?

I am trying to write XSLT file for following input XML to output XML, is it possible XSLT to convert the value of input xml as node in output XML? how can I implement this?
Input XML
<?xml version="1.0" encoding="UTF-8"?>
<Rows>
<Row><xml_data_name/> <xml_data_value/> </Row>
<Row><xml_data_name>persons</xml_data_name> <xml_data_value/> </Row>
<Row><xml_data_name>person</xml_data_name> <xml_data_value/> </Row>
<Row><xml_data_name>username</xml_data_name> <xml_data_value>JS1</xml_data_value> </Row>
<Row><xml_data_name>name</xml_data_name> <xml_data_value/> </Row>
<Row><xml_data_name>name</xml_data_name> <xml_data_value>John</xml_data_value> </Row>
<Row><xml_data_name>name</xml_data_name> <xml_data_value/> </Row>
<Row><xml_data_name>family-name</xml_data_name> <xml_data_value/> </Row>
<Row><xml_data_name>family-name</xml_data_name> <xml_data_value>Smith</xml_data_value> </Row>
<Row><xml_data_name>family-name</xml_data_name> <xml_data_value/> </Row>
<Row><xml_data_name>person</xml_data_name> <xml_data_value/> </Row>
<Row><xml_data_name>person</xml_data_name> <xml_data_value/> </Row>
<Row><xml_data_name>username</xml_data_name> <xml_data_value>MI1</xml_data_value> </Row>
<Row><xml_data_name>name</xml_data_name> <xml_data_value/> </Row>
<Row><xml_data_name>name</xml_data_name> <xml_data_value>Morka</xml_data_value> </Row>
<Row><xml_data_name>name</xml_data_name> <xml_data_value/> </Row>
<Row><xml_data_name>family-name</xml_data_name> <xml_data_value/> </Row>
<Row><xml_data_name>family-name</xml_data_name> <xml_data_value>Ismincius</xml_data_value> </Row>
<Row><xml_data_name>family-name</xml_data_name> <xml_data_value/> </Row>
<Row><xml_data_name>person</xml_data_name> <xml_data_value/> </Row>
<Row><xml_data_name>persons</xml_data_name> <xml_data_value/> </Row>
<Row><xml_data_name/> <xml_data_value/> </Row>
</Rows>
Output XML
<?xml version="1.0" ?>
<persons>
<person username="JS1">
<name>John</name>
<family-name>Smith</family-name>
</person>
<person username="MI1">
<name>Morka</name>
<family-name>Ismincius</family-name>
</person>
</persons>
You could certainly use xsl:element like
<xsl:template match="Row">
<!-- Note {} brackets in name attribute -->
<xsl:element name="{xml_data_name}">
<xsl:value-of select="xml_data_value" />
</xsl:element>
</xsl:template>
What would be greater problem is a structure of output because it is not easy to decide which rows should be nested, which rows should transform into an attribute rather than element etc.
Well, that's one of the weirdest data formats I've ever seen! Are you sure you can't get whatever produced this to produce something more reasonable?
I think the solution has to be recursion: you want a function that takes a sequence of rows as input; it outputs an element whose name is the name of the first element in the sequence with no data value and whose content is obtained by a recursive call that passes all rows after that first row up to the next row with no data value and the same name, then calls itself to process all rows after that row. Not easy, and certainly takes more time than I allow myself for answering SO questions!

XSLT 1.0 advanced calculations

I have been banging my head against a wall on this for a while. Our application processes a complex structure XML invoice from another system. The invoice contains rows of information which contain various counts. These counts may or may not contain a value. There is an overall document charge. We need to work out the unit charge. The formula would be the total cost divided by the total of the counts.
I have been working through the examples kindly provided by others regarding summing in XSLT1.0. I can use xsl:call-template to get the sum of the counts, but I don't know how to apply the result to the calculate the unit price.
Sample XML
<Document>
<Row>
<Count1>
<Value>10</Value>
</Count1>
<Count2>
<Value/>
</Count2>
</Row>
<Row>
<Count1>
<Value>5</Value>
</Count1>
<Count2>
<Value>6</Value>
</Count2>
</Row>
<Row>
<Count1>
<Value>2</Value>
</Count1>
<Count2>
<Value>3</Value>
</Count2>
</Row>
<Charge>
<Value>260</Value>
</Charge>
</Document>
If I could see how to get the following XML output that would probably show me what I need.
<Document>
<Row>
<Total>10</Total>
<UnitPrice>10</UnitPrice>
</Row>
<Row>
<Total>11</Total>
<UnitPrice>10</UnitPrice>
</Row>
<Row>
<Total>15</Total>
<UnitPrice>10</UnitPrice>
</Row>
</Document>
Many thanks in advance
You just need to call sum() on the required Values, like so:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/Document">
<Document>
<xsl:apply-templates select="Row"/>
</Document>
</xsl:template>
<xsl:template match="Row">
<Row>
<Total>
<xsl:value-of select="sum(./*[Value>0]/Value)"/>
</Total>
<UnitPrice>10</UnitPrice>
</Row>
</xsl:template>
</xsl:stylesheet>
This gives the output:
<Document>
<Row>
<Total>10</Total>
<UnitPrice>10</UnitPrice>
</Row>
<Row>
<Total>11</Total>
<UnitPrice>10</UnitPrice>
</Row>
<Row>
<Total>5</Total>
<UnitPrice>10</UnitPrice>
</Row>
</Document>