I am using an XSL when clause to transform one XML file to another XML file. I need to use something like an "exists" function in my when test.
Here's an example source XML:
<People>
<Person personid="1" location="US" fullname="John Doe"/>
<Person personid="2" location="US" fullname="Jane Doe"/>
</People>
<Nicknames>
<Nickname personid="1" nname="Johnny D"/>
</Nicknames>
Here's my example XSL:
<xsl:element name="HASNICKNAME">
<xsl:choose>
<!-- If nickname exists in source XML, return true -->
<xsl:when test="boolean exists function"
<xsl:text>TRUE</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>FALSE</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
Can someone help with the exists part?
Suppose the variable $personid contains the #personid of the Person you are checking, then this only checks existence:
<xsl:when test="boolean(//Nickname[#personid=$personid]/#nname)">
For similar issues I normally prefer to check for a non-empty/non-whitespace value:
<xsl:when test="normalize-space(//Nickname[#personid=$personid]/#nname)!=''">
If you use a key like <xsl:key name="nn" match="//Nickname" use="#personid"/>, the following is also possible:
<xsl:when test="normalize-space(key('nn',$personid)/#nname)!=''">
The latter does not need the $personid variable but can directly work with the #personid of the Person you are checking…
Related
Still new to this forum and XSLT, already searched but could not find the correct solution.
i am trying to get the right concat after the choose, if i match the condition 208 or 906 is still get LX1234 as combination, it always ends up on the otherwise as solution. the XSLT is build in 2.0 so both solutions will work for me.
<xsl:for-each select="XXX/Envelope/PickingList/Line/Lot">
<articleLine type="tag">
<articleCode>
<xsl:choose>
<xsl:when test="XXX/Envelope/GLN_Supplier =208">
<xsl:value-of select="concat('AV',../ArticleCodeSupplier)"/>
</xsl:when>
<xsl:when test="XXX/Envelope/GLN_Supplier =906">
<xsl:value-of select="concat('KR',../ArticleCodeSupplier)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat('LX',../ArticleCodeSupplier)"/>
</xsl:otherwise>
</xsl:choose>
</articleCode>
Edit XML input, thank you for pointing that out #michael.hor257k
<?xml version='1.0' encoding='ISO-8859-1'?>
<XXX>
<Envelope>
<InterchangeControlReference>995566</InterchangeControlReference>
<GLN_Supplier>906</GLN_Supplier>
<GLN_Customer>541</GLN_Customer>
<PickingList>
<PickingListNumber>9</PickingListNumber>
<PickingDate>2019-08-01</PickingDate>
<OrderNumberSupplier>12345</OrderNumberSupplier>
<OrderNumberCustomer>EDI Test 1</OrderNumberCustomer>
<EarliestDeliveryDate>2019-10-09</EarliestDeliveryDate>
<EarliestDeliveryTime>14:13:39</EarliestDeliveryTime>
<LastDeliveryDate>2019-10-09</LastDeliveryDate>
<LastDeliveryTime>14:13:39</LastDeliveryTime>
<GLN_Supplier>215</GLN_Supplier>
<GLN_WarehouseAddressSupplier>541</GLN_WarehouseAddressSupplier>
<GLN_Customer>000</GLN_Customer>
<GLN_DeliveryAddressCustomer>000</GLN_DeliveryAddressCustomer>
<GLN_CarrierAddressCustomer></GLN_CarrierAddressCustomer>
<DeliveryName>CLIENTNAME</DeliveryName>
<DeliveryNameContactperson></DeliveryNameContactperson>
<DeliveryTelephoneNumber></DeliveryTelephoneNumber>
<DeliveryAddress>CLIENTADDRESS</DeliveryAddress>
<DeliveryAddress2></DeliveryAddress2>
<DeliveryHouseNumber>0</DeliveryHouseNumber>
<DeliveryHouseNumberExtra></DeliveryHouseNumberExtra>
<DeliveryPostalCode>1111 aa</DeliveryPostalCode>
<DeliveryCity>PLACE</DeliveryCity>
<DeliveryCountryISO>NL</DeliveryCountryISO>
<DeliveryCustomsExcise></DeliveryCustomsExcise>
<DeliveryMethod>DDP</DeliveryMethod>
<DeliveryIncoterm>DDP</DeliveryIncoterm>
<DeliveryIncotermCity></DeliveryIncotermCity>
<Remarks_Pickinglist>REMARKS WAREHOUSE</Remarks_Pickinglist>
<Remarks_Packinglist>REMARKS FREIGHTBILL</Remarks_Packinglist>
<Remarks_Delivery></Remarks_Delivery>
<CustomsExcise>true</CustomsExcise>
<Test>false</Test>
<Line>
<LineNumber>1</LineNumber>
<EAN_Article>528</EAN_Article>
<ArticleCodeSupplier>1234</ArticleCodeSupplier>
<ArticleCodeCustomer></ArticleCodeCustomer>
<UnitToPick>Fles</UnitToPick>
<ArticleDescription>VINE WINE</ArticleDescription>
<QuantityToPick>21</QuantityToPick>
<QuantityToPickInOrderUnit>21</QuantityToPickInOrderUnit>
<UnitOrdered>Fles</UnitOrdered>
<Lot>
<LotCode>72</LotCode>
<BatchCode>3</BatchCode>
<YearOfProduction>2017</YearOfProduction>
<QuantityToPick>21</QuantityToPick>
</Lot>
</Line>
<Line>
<LineNumber>2</LineNumber>
<EAN_Article>081</EAN_Article>
<ArticleCodeSupplier>5678</ArticleCodeSupplier>
<ArticleCodeCustomer></ArticleCodeCustomer>
<UnitToPick>Fles</UnitToPick>
<ArticleDescription>CHAMPAGNE</ArticleDescription>
<QuantityToPick>10</QuantityToPick>
<CountryOfOriginISO>ES</CountryOfOriginISO>
<QuantityToPickInOrderUnit>10</QuantityToPickInOrderUnit>
<UnitOrdered>Fles</UnitOrdered>
<Lot>
<LotCode>5</LotCode>
<BatchCode>4</BatchCode>
<YearOfProduction>2019</YearOfProduction>
<QuantityToPick>10</QuantityToPick>
<CountryOfOriginISO>ES</CountryOfOriginISO>
</Lot>
</Line>
</PickingList>
</Envelope>
</XXX>
The instruction:
<xsl:for-each select="XXX/Envelope/PickingList/Line/Lot">
puts you in the context of Lot. From this context, the test in:
<xsl:when test="XXX/Envelope/GLN_Supplier =208">
will return false, because the relative path XXX/Envelope/GLN_Supplierselects nothing. You will get a different result if you make the path an absolute one:
<xsl:when test="/XXX/Envelope/GLN_Supplier =208">
Of course, it would be more efficient to do this test once outside the xsl:for-each block and make the result available in a variable - for example:
<xsl:template match="/XXX">
<output>
<xsl:variable name="articleCodePrefix">
<xsl:choose>
<xsl:when test="Envelope/GLN_Supplier=208">AV</xsl:when>
<xsl:when test="Envelope/GLN_Supplier=906">KR</xsl:when>
<xsl:otherwise>LX</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:for-each select="Envelope/PickingList/Line/Lot">
<articleLine type="tag">
<articleCode>
<xsl:value-of select="$articleCodePrefix"/>
<xsl:value-of select="../ArticleCodeSupplier"/>
</articleCode>
</articleLine>
</xsl:for-each>
</output>
</xsl:template>
I'm trying to write an XSLT function to select between some dates. I have parameters that are being converted to xs:date and then used to get the number of days between two of them, and format them appropriately. For some reason, the termDate variable is being reported as undefined, even though I can see in the Variables and Nodes/Values Set panels in Oxygen that the parameter references and element that does have a value.
<xsl:function name="my:getStatusDate">
<xsl:param name="rehire"/>
<xsl:param name="term"/>
<xsl:param name="hire"/>
<xsl:variable name="rehireDate" select="xs:date($rehire)" as="xs:date"/>
<xsl:variable name="termDate" select="xs:date($term)" as="xs:date"/>
<xsl:variable name="hireDate" select="xs:date($hire)" as="xs:date"/>
<xsl:variable name="dayDiffTermRehire" select="days-from-duration($termDate - $rehireDate)" as="xs:integer"/>
<xsl:choose>
<xsl:when test="$term != '' and not($term)">
<xsl:choose>
<xsl:when test="$dayDiffTermRehire > xs:integer(91)">
<xsl:value-of select="format-date($rehireDate, '[M01]/[D01]/[Y0001]')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="format-date($hireDate, '[M01]/[D01]/[Y0001]')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="format-date($hireDate, '[M01]/[D01]/[Y0001]')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:function>
The call site looks like this:
<ExpectedStatusEffectiveDate><xsl:value-of select="my:getStatusDate(RecentHireDate, TermDate, PreviousHireDate)"/></ExpectedStatusEffectiveDate>
A sample XML source looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<Data>
<Entry>
<EmployeeFirstName>John</EmployeeFirstName>
<EmployeeLastName>Doe</EmployeeLastName>
<BirthDate>1940-01-01-01:00</BirthDate>
<RecentHireDate>1970-05-20-07:00</RecentHireDate>
<PreviousHireDate>1970-05-20-07:00</PreviousHireDate>
</Entry>
<Entry>
<EmployeeFirstName>Jane</EmployeeFirstName>
<EmployeeLastName>Doe</EmployeeLastName>
<BirthDate>1970-11-25-08:00</BirthDate>
<RecentHireDate>2003-12-22-08:00</RecentHireDate>
<PreviousHireDate>1970-06-19-07:00</PreviousHireDate>
<TermDate>2000-01-13-08:00</TermDate> <!-- NOTE: this entry HAS a TermDate -->
</Entry>
</Data>
Any idea why the termDate would be undefined in BOTH cases?
I'm going to chalk this up to an Oxygen bug. I'm not sure what changed, but after isolating the function into its own stylesheet, it started working. I then copied it back into the original, and everything seemed to work.
I'm strugling with a Choose statement and the corresponding Test-Clause.
If have the following XML (just an extract) which represents an datamodel exportet from Enterprise Architect as XMI:
<xmi:XMI xmi:version="2.1" xmlns:uml="http://schema.omg.org/spec/UML/2.1" xmlns:xmi="http://schema.omg.org/spec/XMI/2.1" xmlns:thecustomprofile="http://www.sparxsystems.com/profiles/thecustomprofile/1.0" xmlns:EAUML="http://www.sparxsystems.com/profiles/EAUML/1.0"> <xmi:Documentation exporter="Enterprise Architect" exporterVersion="6.5"/> <uml:Model xmi:type="uml:Model" name="EA_Model" visibility="public"> <packagedElement xmi:type="uml:Package" xmi:id="EAPK_F3388CFE_57A7_4d84_8866_3FB3AADE565A" name="Data Model - SQLServer2012" visibility="public">
<packagedElement xmi:type="uml:Artifact" xmi:id="EAID_B62341D4_41C6_4c83_A60A_4CA65C2E185E" name="Database SQLServer2012" visibility="public"/>
<packagedElement xmi:type="uml:Package" xmi:id="EAPK_BA7676C5_40BC_4bd9_A0F5_F6B15E534E8E" name="Logical Model" visibility="public">
<packagedElement xmi:type="uml:Class" xmi:id="EAID_2DC36189_CCFB_40bf_A1CB_CD4FB08FE8B5" name="AnamneseStatus" visibility="public">
<ownedAttribute xmi:type="uml:Property" xmi:id="EAID_9BBF5184_37F8_4729_9DC1_7ED3B4D8FC98" name="RCHIUNET05_ContextKey" visibility="public" isStatic="false" isReadOnly="false" isDerived="false" isOrdered="true" isUnique="false" isDerivedUnion="false">
<lowerValue xmi:type="uml:LiteralInteger" xmi:id="EAID_LI000001_37F8_4729_9DC1_7ED3B4D8FC98" value="1"/>
<upperValue xmi:type="uml:LiteralInteger" xmi:id="EAID_LI000002_37F8_4729_9DC1_7ED3B4D8FC98" value="1"/>
<type xmi:idref="EASQL_Server_2012_nvarchar"/>
</ownedAttribute>
<ownedAttribute xmi:type="uml:Property" xmi:id="EAID_BC1F93D0_A7F4_474c_A27E_26D3ABCCFB7B" name="MRNCmpdId" visibility="public" isStatic="false" isReadOnly="false" isDerived="false" isOrdered="false" isUnique="true" isDerivedUnion="false">
<lowerValue xmi:type="uml:LiteralInteger" xmi:id="EAID_LI000003_A7F4_474c_A27E_26D3ABCCFB7B" value="1"/>
<upperValue xmi:type="uml:LiteralInteger" xmi:id="EAID_LI000004_A7F4_474c_A27E_26D3ABCCFB7B" value="1"/>
<type xmi:idref="EASQL_Server_2012_nvarchar"/>
</ownedAttribute>
..........
So with my XSL I will loop throug the relevant nodes and extract the tablenames and attributes. this works without problem. Now I need to translate the EA datatype into another datatype definition.
Lets say: EASQL_Server_2012_nvarchar needs to become System.String
The XSL doing this looks like this (since there are other datatypes the Choose Statement will be longer than showed here):
<xsl:for-each select="ownedAttribute[#xmi:type='uml:Property']">
<xsl:text disable-output-escaping="yes"><</xsl:text>
<xsl:value-of select="'Element Name="'"/>
<xsl:value-of select="#name"/>
<xsl:value-of select="'" '"/>
<xsl:choose>
<xsl:when test="#xmi:idref = 'EASQL_Server_2012_nvarchar'">
<xsl:value-of select="'Type="'"/>
<xsl:value-of select="'System.String'"/>
<xsl:value-of select="'" '"/>
<xsl:value-of select="'MaxLength="'"/>
<xsl:value-of select="'400'"/>
<xsl:value-of select="'" '"/>
</xsl:when>
<xsl:when test="#xmi:idref = 'EASQL_Server_2012_int'">
<xsl:value-of select="'Type="'"/>
<xsl:value-of select="'System.Int32'"/>
<xsl:value-of select="'" '"/>
</xsl:when>
......
Now my problem is, that it will not hit the test conditions and always run into the "otherwise" statement.
Does somebody see why the test condition is not working?
Thank you for any help on this.
Cheers
Sandro
I suspect that instead of:
<xsl:when test="#xmi:idref = 'EASQL_Server_2012_nvarchar'">
you want to do:
<xsl:when test="type/#xmi:idref = 'EASQL_Server_2012_nvarchar'">
since in the partial example you have posted, ownedAttribute (which is your context node when you run this test) has no xmi:idref attribute, but its child element type does.
P.S. I don't know what you're doing overall, but I cringe whenever I see:
<xsl:text disable-output-escaping="yes"><</xsl:text>
This should never be necessary. If - as it seems - you're not outputting XML, set the output method to text. Then it's not necessary to disable output escaping.
I'm trying to substitute an empty value in a csv file with a number.
Here's an example:
1111111,,11222
So I tried this:
<xsl:template match="/">
<xsl:apply-templates select="//tr" />
</xsl:template>
<xsl:template match="tr">
<document>
<content name="title">
<xsl:value-of select="td[1]/text()" />
</content>
<content name="loanID">
<xsl:value-of select="td[1]/text()" />
</content>
<content name="cNumber">
<xsl:variable name="score" select="td[2]/text()" />
<xsl:choose>
<xsl:when test="$score=''">
<xsl:value-of select="550" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="td[18]/text()" />
</xsl:otherwise>
</xsl:choose>
</content>
</document>
</xsl:template>
I constantly get a null value for the cNumber node when the value is empty in the row, and I'm expecting my code to substitute the empty value for '550'. What am I doing wrong? I checked this question here: and it seems like this should work. I'm using a special application for this but my guess is the fault lies with me.
Thanks
If the td element is empty, then td/text() returns an empty sequence/node-set, and when you compare an empty sequence to '', the result is false. This is one of the reasons that many people advise against using text(). You're not interested here in the text node, you are interested in the string value of the td element, and to get that you should use
<xsl:variable name="score" select="string(td[2])" />
Your other uses of text() are also incorrect, though you're only likely to see a problem if your XML input contains comments or processing instructions. But you should get out of this coding habit, and replace
<xsl:value-of select="td[1]/text()" />
by
<xsl:value-of select="td[1]" />
As a general rule, when you see /text() in an XPath expression it's usually wrong.
I have a variable in XSLT called variable_name which I am trying to set to 1, if the Product in question has attributes with name A or B or both A & B.
<xsl:variable name="variable_name">
<xsl:for-each select="product/attributes">
<xsl:if test="#attributename='A' or #attributename='B'">
<xsl:value-of select="1"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
Is there any way to match multiple strings using the if statement, as mine just matches if A is present or B is present. If both A & B are present, it does not set the variable to 1. Any help on this would be appreciated as I am a newbie in XSLT.
You can use xsl:choose statement, it's something like switch in common programming languages:
Example:
<xsl:variable name="variable_name">
<xsl:for-each select="product/attributes">
<xsl:choose>
<xsl:when test="#attributename='A'">
1
</xsl:when>
<xsl:when test=" #attributename='B'">
1
</xsl:when>
<!--... add other options here-->
<xsl:otherwise>1</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:variable>
This will set new variable with name variable_name with the value of attribute product/attributes.
For more info ... http://www.w3schools.comwww.w3schools.com/xsl/el_choose.asp
EDIT: And another way (a little dirty) by OP's request:
<xsl:variable name="variable_name">
<xsl:for-each select="product/attributes">
<xsl:if test="contains(text(), 'A') or contains(text(), 'B')">
1
</xsl:if>
</xsl:for-each>
</xsl:variable>
It will be helpful if you provide the xml you're writing your xslt against.
This might not help...
Is it 'legal' to have two XML element attributes with the same name (eg. <element x="1" x="2" />)?
Is this what you are trying to process? Try parsing your XML file through xmllint or something like it to see if it is valid.
xmllint --valid the-xml-file.xml
My guess is that you will get a 'attribute redefined' error.