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.

有帮助吗?

解决方案

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.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top