Title: How do I display an element's attribute based on complex condition?
Tags: xml;xslt
Question: I have a xml document that I would like to display Number attribute from <CrossReferenceNumber&gt; element
In my xslt the Number is inside <ext:SupersededProtectionOrderID&gt; element.
Xml document can have <Type Op="A" Word="SBJO"&gt;Signed By Judicial Officer</Type&gt;
<Type Op="A" Word="SBJO"&gt;Signed By Judicial Officer – Corrected’</Type&gt;
Here are the conditions:
Condition one
If ProtectionOrder/CrossReferenceNumbers/CrossReferenceNumber/Type = ‘OFP System Number’
ProtectionOrders/ProtectionOrder/Statuses/Status/Type = Signed By Judicial Officer has an Op = “A”
display
ProtectionOrder/CrossReferenceNumbers/CrossReferenceNumber/Number in the ext:SupersededProtectionOrderID element in xslt.
Condition two
If ProtectionOrder/CrossReferenceNumbers/CrossReferenceNumber/Type = ‘OFP System Number’
ProtectionOrders/ProtectionOrder/Statuses/Status/Type = ‘Signed By Judicial Officer – Corrected’
and has Op = ‘A’
display
ProtectionOrder/CrossReferenceNumbers/CrossReferenceNumber/Number
in xsl's ext:SupersededProtectionOrderID element.
Desired output
<ext:SupersededProtectionOrderID&gt;OFP System Number</ext:SupersededProtectionOrderID&gt;
My xml
<Integration xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:tsg="http://tsgweb.com" xmlns:IXML="http://tsgweb.com" xmlns:CMCodeQueryHelper="urn:CMCodeQueryHelper" PackageID="BCA PO Notification" MessageID="67177928" xmlns=""&gt;
<ProtectionOrders&gt;
<ProtectionOrder Op="E" InternalProtectionOrderID="932"&gt;
<ProtectionOrderNumber&gt;201500845</ProtectionOrderNumber&gt;
<Type Word="OFP"&gt;Order for Protection</Type&gt;
<Statuses&gt;
<Status Op="A"&gt;
<Current&gt;true</Current&gt;
<Active&gt;Yes</Active&gt;
<Date Op="A"&gt;09/01/2015</Date&gt;
<Type Op="A" Word="SBJO"&gt;Signed By Judicial Officer</Type&gt;
<TimestampCreate Op="A"&gt;09/01/2015 12:39:49:763</TimestampCreate&gt;
</Status&gt;
<Status&gt;
<Current&gt;false</Current&gt;
<Active&gt;No</Active&gt;
<Date&gt;09/01/2015</Date&gt;
<Type Word="DRAFT"&gt;Draft</Type&gt;
<TimestampCreate&gt;09/01/2015 12:39:43:207</TimestampCreate&gt;
</Status&gt;
</Statuses&gt;
<CrossReferenceNumbers&gt;
<CrossReferenceNumber&gt;
<Type Word="NCICNUM"&gt;NCIC Number</Type&gt;
<Number&gt;Testing123</Number&gt;
</CrossReferenceNumber&gt;
</CrossReferenceNumbers&gt;
<TimestampCreate&gt;09/01/2015 12:39:43:140</TimestampCreate&gt;
<TimestampChange&gt;09/01/2015 12:39:49:750</TimestampChange&gt;
</ProtectionOrder&gt;
</ProtectionOrders&gt;
</Case&gt;
<ProtectionOrder Op="E" InternalProtectionOrderID="932" xmlns:user="http://tylertechnologies.com"&gt;
<ProtectionOrderNumber&gt;201500845</ProtectionOrderNumber&gt;
<Type Word="OFP"&gt;Order for Protection</Type&gt;
<Statuses&gt;
<Status Op="A"&gt;
<Current&gt;true</Current&gt;
<Active&gt;Yes</Active&gt;
<Date Op="A"&gt;09/01/2015</Date&gt;
<Type Op="A" Word="SBJO"&gt;Signed By Judicial Officer</Type&gt;
<TimestampCreate Op="A"&gt;09/01/2015 12:39:49:763</TimestampCreate&gt;
</Status&gt;
<Status&gt;
<Current&gt;false</Current&gt;
<Active&gt;No</Active&gt;
<Date&gt;09/01/2015</Date&gt;
<Type Word="DRAFT"&gt;Draft</Type&gt;
<TimestampCreate&gt;09/01/2015 12:39:43:207</TimestampCreate&gt;
</Status&gt;
</Statuses&gt;
<CrossReferenceNumbers&gt;
<CrossReferenceNumber&gt;
<Type Word="NCICNUM"&gt;OFP System Number</Type&gt;
<Number&gt;Testing123</Number&gt;
</CrossReferenceNumber&gt;
</CrossReferenceNumbers&gt;
</ProtectionOrder&gt;
My xslt code
<?xml version="1.0" encoding="UTF-8"?&gt;
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:exc="http://www.courts.state.mn.us/ProtectionOrderServiceExchange/1.0" xmlns:ext="http://www.courts.state.mn.us/ProtectionOrderExtension/1.0"&gt;
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/&gt;
<xsl:template name="ProtectionOrder"&gt;
<!--SupersededProtectionOrderID--&gt;
<ext:SupersededProtectionOrderID&gt;
<xsl:choose&gt;
<xsl:when test="(Statuses/Status/Type/@Op='A') and count(CrossReferenceNumbers/CrossReferenceNumber/Type='OFP System Number')&gt;0"&gt;
<xsl:value-of select="Number"/&gt;
</xsl:when&gt;
<xsl:otherwise&gt;
<xsl:value-of select="/Integration/ProtectionOrder[@InternalProtectionOrderID=current()/MNProtectionOrderAdditional/@SupersededProtectionOrderID]/ProtectionOrderNumber"/&gt;
</xsl:otherwise&gt;
</xsl:choose&gt;
</ext:SupersededProtectionOrderID&gt;
</xsl:template&gt;
</xsl:stylesheet&gt;
Comment: Abel where do I add the template code? Is it after I replace the previous code or before?

Comment: templates are always global in XSLT and their order is irrelevant.

Here is the accepted answer: Note: in your requirements, you explain when <Number&gt; is to be output, but this is not an attribute, as mentioned in your title.
Replace this:
<ext:SupersededProtectionOrderID&gt;
<xsl:choose&gt;
<xsl:when test="(Statuses/Status/Type/@Op='A') and count(CrossReferenceNumbers/CrossReferenceNumber/Type='OFP System Number')&gt;0"&gt;
<xsl:value-of select="Number"/&gt;
</xsl:when&gt;
<xsl:otherwise&gt;
<xsl:value-of select="/Integration/ProtectionOrder[@InternalProtectionOrderID=current()/MNProtectionOrderAdditional/@SupersededProtectionOrderID]/ProtectionOrderNumber"/&gt;
</xsl:otherwise&gt;
</xsl:choose&gt;
</ext:SupersededProtectionOrderID&gt;
With this:
<!-- assuming your named template has the correct context item! --&gt;
<xsl:apply-templates select="Statuses/Status/Type" mode="number" /&gt;
And add this:
<xsl:template mode="number" match="Type
[@Op = 'A'][
. = 'Signed By Judicial Officer'
or . = 'Signed By Judicial Officer - Corrected'
]"&gt;
<xsl:apply-templates mode="number"
select="../../../CrossReferenceNumbers
/CrossReferenceNumber[Type='OFP System Number'][1]" /&gt;
</xsl:template&gt;
<xsl:template match="CrossReferenceNumber" mode="number"&gt;
<ext:SupersededProtectionOrderID&gt;
<xsl:value-of select="Number"/&gt;
</ext:SupersededProtectionOrderID&gt;
</xsl:template&gt;
This will work for your first requirement. Using apply-templates with conditions that depend on the number of elements, or the existence of one is usually much easier than trying your way with xsl:if and xsl:choose, if not only because you get the advantage of focus and context change. Plus it will work regardless your input size, other elements, or different positions or even depth.
EDIT: edited to work with both your conditions.
Comment for this answer: I have not been able to make the suggested changes to my code. Isn't there an easier way of doing this?
Comment for this answer: It is somebody else code and she want me to use choose. Is there a way to use choose?
Comment for this answer: I totally understand what you said lol. I will work through until it is working for me. I will also read more and practice using templates. I will mark your response as answer
Comment for this answer: I was able to figure out how to add the code into my xslt and it is now working. Again thank you @Abel.
Comment for this answer: I am developing in both xslt and vb.net. Any advice in regard to what I need to do to get better? I know more coding and reading right?
Comment for this answer: Thanks for the information. I use Altova processor.  My template is working however I am not sure how to display something else if the template information is not provided. I mean my conditions also involve displaying `` when the `Number` is not available and when `ProtectionOrderNumber` is provided instead. How to I display this?
Comment for this answer: Thanks. I actually figured it out after playing with the code for a bit.
Comment for this answer: @Winston, what problem are you facing? If this is your first encounter with XSLT and the original code is not yours, it can be daunting, but in that case I really suggest reading a quick tutorial, it'll save you loads of headaches.
Comment for this answer: @Winston: `xsl:choose` is a bad design choice, unless it is the only option (i.e. when dealing with non-nodes). XSLT is about template matching, which is where its power lies. Rewriting that with `xsl:choose` is lengthy, error-prone and complex. It is the imperative way of programming in XSLT and well, _XSLT is not an imperative, but a declarative + functional language_.
Comment for this answer: @Winston, besides that, there was a reason when I suggested this edit to your code: with the `xsl:choose` currently in place, it is next to impossible, if not impossible, to get what you want. Trust me, I have been working with XSLT for over 10 years, you don't want to go there ;).
Comment for this answer: @Winston, glad you got it working! Happy coding. Hope you'll get to appreciate XSLT if you have to deal with it a bit more often :).
Comment for this answer: @Winston: there are a couple of good books (both online and physical) that can really speed up your understanding and coding skills in regards to XSLT. Since you use VB.NET, it means you could choose an XSLT 2.0 or 3.0 processor (Microsoft only supports the over 15 years old standard of XSLT 1.0). Have a look at upcoming [Exselt](http://exselt.net) (it's my own) and [Saxon](http://saxonica.com), which comes with a .NET version as well.
Comment for this answer: @Winston, that's really a new question. StackOverflow is not meant for long threads, it is about questions that can be answered. In short, just ask [a new question](http://stackoverflow.com/questions/ask) and make sure your info is complete (as with [mcve]) and you'll get a prompt reply (maybe not from me, but there are many active XSLT specialists around here). Oh, and always mention your XSLT version and processor, it'll help answering correctly.
Comment for this answer: @Winston, that's the best way to learn. Glad you got it working! :)


{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 1, 'CommentCount': 2, 'ContentLicense': 'CC BY-SA 3.0', 'CreationDate': '2015:00:09/01/15', 'FavoriteCount': None, 'PostTypeId': 1, 'Tags': '<xml><xslt>', 'Title': "How do I display an element's attribute based on complex condition?", 'ViewCount': 138, 'id': 32340487, 'user_AboutMe': None, 'user_AccountId': None, 'user_DisplayName': None, 'user_Reputation': None, 'user_Views': None, 'user_id': None}}