Xslt - How do you check for a grandchild node with a certain path name. (xpath 1.0)

StackOverflow https://stackoverflow.com/questions/16963732

  •  31-05-2022
  •  | 
  •  

質問

What I want to do is given an element as context, I want to determine if it has a child with a given name and determine if that child has a node with a given name so I can do operations with it. It is important that I do this in XPath 1.0 syntax.

The code that I've gotten so far is this.

<xsl:for-each select="child::*">
  <xsl:if test="contains(name(), 'description')">
    <xsl:for-each select="child::*">
      <xsl:if test="contains(name(), 'text')">
        <xsl:value-of select="node()"/>
      </xsl:if>
</xsl:for-each>
  </xsl:if>
</xsl:for-each>

It works, but it's big and ugly and I know that there's a way to condense it. The for-eachs there are unnecessary, since I'm only expecting one child node to be named description, and for it to only have one text node.

I feel like this solution should work

<xsl:for-each select="./description/text">
  ..
</xsl:for-each>

But it isn't, and I'm not really good enough with XPath Syntax to know why.

The reason I'm asking is because though I've found answers that detect whether a child node has a name, and I've found answers that can get to that child node's context, I haven't found an answer that combines the two, though maybe I just haven't been searching hard enough, in which case I apologize.

Edit: Woops, sorry yeah I forgot to mention that the contains() part of the code was also just a hack because I wasn't sure how to compare their values with equality.

Also as long as the answer is there, <xsl:for-each select="description/text"> does not work either.

A sample of the XML in question is this

<leaf>
  <description>
    <text> Various Words
    </text>
  </description>
</leaf>

where the context is the leaf and I am trying to get to the text node.

Edit: The Second Coming:

The problem for me was that my XSLT file was using a default namespace (in my case named a). If I had added that then Borodin's answer would have been correct.

To be specific, this is the code which ended up working for me in the end, in case anyone wants to know.

<xsl:for-each select="a:description/a:text>
  <xsl:value-of select="node()"/>
</xsl:for-each>

Thanks Guys ^-^

役に立ちましたか?

解決

Do you really want to check whether the element names contain those strings? Or, as your narrative says, do you want elements with that exact name?

To do something like what you have already written, use

<xsl:for-each select="*[contains(name(), 'description')]/*[contains(name(), 'text')]">
  <xsl:value-of select="node()"/>
</xsl:for-each>

But if you know the complete names it is a lot neater:

<xsl:for-each select="description/text">
  <xsl:value-of select="node()"/>
</xsl:for-each>

If that doesn't work then we need to see more of your source XML and your transform.


Update

If I use this XML

<leaf>
  <description>
    <text>Various Words</text>
  </description>
  <description>
    <text>More Words</text>
  </description>
  <description>
    <text>Other Words</text>
  </description>
</leaf>

and apply this stylesheet

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="text"/>

  <xsl:template match="/leaf">
    <xsl:for-each select="description/text">
      <xsl:value-of select="."/>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

the output is the expected Various WordsMore WordsOther Words. I don't know how to help you unless you describe your situation better, except to say that transforms should be written with another template rather than for-each wherever possible. Like this variation which produces the same output as above.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="text"/>

  <xsl:template match="/leaf">
    <xsl:apply-templates select="description/text"/>
  </xsl:template>

  <xsl:template match="text">
    <xsl:value-of select="."/>
  </xsl:template>

</xsl:stylesheet>
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top