0

I have an XML document like this:

(p is defined previously)

<p:Players>
<p:Player>
<p:Name>David</p:Name>
<p:Club>
<p:Name>Madrid</p:Name>
</p:Club>
<p:PreviousClubs>
<p:Club><p:Name>Milan</p:Name></p:Club>
<p:Club><p:Name>Manchester</p:Name></p:Club>
</p:PreviousClubs>
</p:Player>
<p:Player>
<p:Name>Alex</p:Name>
<p:Club>
<p:Name>Madrid</p:Name>
</p:Club>
<p:PreviousClubs>
<p:Club><p:Name>Birmingham</p:Name></p:Club>
<p:Club><p:Name>Manchester</p:Name></p:Club>
</p:PreviousClubs>
</p:Player>
<p:Player>
<p:Name>Fred</p:Name>
<p:Club>
<p:Name>Madrid</p:Name>
</p:Club>
<p:PreviousClubs>
<p:Club><p:Name>Milan</p:Name></p:Club>
<p:Club><p:Name>Birmingham</p:Name></p:Club>
</p:PreviousClubs>
</p:Player>
</p:Players>

I'd like to get the Names of all the players who've previously played for a given club.

This is what I have so far, but it isn't picking anything up:

/*[1]/p:Player[p:PreviousClubs/p:Club/p:Name='Manchester']/p:Name/text()

I expect that to return

David
Alex

But I get nothing

Can someone see where I'm going wrong?

The namespace and its prefix of p: is correct - have used elsewhere and its fine. I feel my logic around selecting the particular parent node is wrong...

I need to stick to XSLT 1.0 as its BizTalk driven.

Dijkgraaf
  • 11,049
  • 17
  • 42
  • 54
Chris
  • 2,471
  • 25
  • 36
  • 2
    I think it could be to do with the namespace. In your XML sample, you have not specified a namespace at all, so all the elements belong to NO namespace. If you are using a namespace prefix of **p** in your xpath expression in your XSLT, then it will be looking for elements within what ever namespace-uri is defined for the **p** prefix. Does your input XML definitely have no namespace defined? – Tim C Nov 08 '12 at 12:31
  • it does have the namespace defined, i was copying quickly rather than copying and pasting - the namespace isnt the issue though - it just doesnt pick up the text value. I copied and pasted the namespace in - i'll edit the xml now so it matches – Chris Nov 08 '12 at 13:19
  • Ah, ok! Could you show the definition of the **p** prefix though, in your XML (i.e the namespace-url, such as ``. You would obviously need to check that the uri is same as specified in the XSLT. It might also help if you showed more of your actual XSLT just in case the problem lies elsewhere. Thanks! – Tim C Nov 08 '12 at 13:29
  • 2
    The XPath expression is definitely doing its job if namespaces are set up correctly. – Thomas W Nov 08 '12 at 13:42
  • lesson learnt, I should use better prefixes than 'p' - I'd got my prefixes mixed up - thanks all for your help - @TimC if you want to put it as an answer so I can accept it? – Chris Nov 09 '12 at 08:51

1 Answers1

1

This is almost certainly an issue with namespaces.

In your XML, you are using a namespace prefix, but there is not a corresponding definition for the namespace. You should really have a definition such as this on the root element

<p:Players xmlns:p="mynamespace">

Then, within your XSLT, you will also need to ensure the same namespace URI is defined.

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:p="mynamespace">

Note that the prefix p doesn't have to be the same. It is the namespace URI that is the important identifier here. If the URI doesn't match what is in the XML, it won't find the elements if you use the prefix.

If you therefore use this XSLT, it should return David and Alex as expected (although you would need to add extra code if you wanted line breaks here)

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:p="mynamespace">

    <xsl:template match="/">
       <xsl:apply-templates 
           select="/*[1]/p:Player[p:PreviousClubs/p:Club/p:Name='Manchester']/p:Name/text()" />
    </xsl:template>
</xsl:stylesheet>

All this means is your original XPath expression is correct! However, you can simplify slightly as there is no need for the [1] at the start. The first / matches the document element, and so /* will match the root element, and because you can only have one root element in well-formed XML, there is no need to qualify it with the index [1]

/*/p:Player[p:PreviousClubs/p:Club/p:Name='Manchester']/p:Name/text()

You could also drop the text() at the end, because the built-in templates will output the text for an element in this case anyway.

Tim C
  • 70,053
  • 14
  • 74
  • 93