user2093335
user2093335

Reputation: 219

Find elements up to a certain point

I have an XPath problem. I need a test condition for any <iframe> that is included in a <part>, but not any <iframe>s that are included in a <chapter>. Note that <chapter>s are included in a <part>.

XML:

<book>
<part id="p1">
    <h1>Add a heading</h1>
    <p>some text here</p>
    <p>more text here</p>
    <div>
        <h2>Add another heading</h2>
        <p>more text</p>
    </div>
    <div class="someDivision">
        <div class="someOtherDivision">
            <h2>Heading</h2>
            <div class="sect">
                <h2>Heading</h2>
                <iframe>Add iframe content</iframe>
            </div>
        </div>
    </div>
    <chapter>
        <h1>Add a chapter heading</h1>
        <p>some chapter text here</p>
        <div class="someDivision">
            <div class="someOtherDivision">
                <h2>Heading</h2>
                <div class="sect">
                    <h2>Heading</h2>
                    <iframe>Add more iframe content</iframe>
                </div>
            </div>
        </div>  
    </chapter>
</part>
<part id="p2">
    <h1>Add a heading</h1>
    <p>some text here</p>
    <p>more text here</p>
    <div>
        <h2>Add another heading</h2>
        <p>more text</p>
    </div>
    <chapter>
        <h1>Add a chapter heading</h1>
        <p>some chapter text here</p>
        <div class="someDivision">
            <div class="someOtherDivision">
                <h2>Heading</h2>
                <div class="sect">
                    <h2>Heading</h2>
                    <iframe>Add more iframe content</iframe>
                </div>
            </div>
        </div>  
    </chapter>
</part>
</book>

XSLT:

<xsl:template match="/">
        <xsl:element name="manifest">
            <xsl:for-each select="//part">
                <xsl:element name="item">
                    <xsl:attribute name="id" select="@id/string()"/>
                    <xsl:if test="//div[@class='someDivision']/div[@class='someOtherDivision']//iframe">
                        <xsl:attribute name="properties" select="'remote-resources'"/>
                    </xsl:if>
                </xsl:element>
            </xsl:for-each>
        </xsl:element>
    </xsl:template>

I get this result:

<manifest>
    <item id="p1" properties="remote-resources"/>
    <item id="p2" properties="remote-resources"/>
</manifest>

But I only want:

<manifest>
    <item id="p1" properties="remote-resources"/>
</manifest>

As there is no <iframe> directly in <part> and not nested within a <chapter>. But I'm not sure how to accomplish this when my XPath will select any <iframe> within a <part> (which includes the ones in a <chapter>.

Upvotes: 0

Views: 32

Answers (1)

michael.hor257k
michael.hor257k

Reputation: 117073

I need to select any <iframe> that is included in a <part>, but not any <iframe>s that are included in a <chapter>.

So how about:

/book/part//iframe[not(ancestor::chapter)]

Added:

If you want to test, from the context of a part, if the current part contains any iframe elements that are not descendants of a chapter, then do something like this:

<xsl:template match="/book">
    <manifest>
        <xsl:for-each select="part">
            <item id="{@id}">
                <xsl:if test=".//iframe[not(ancestor::chapter)]">
                    <!-- code if true -->
                </xsl:if>
            </item>
        </xsl:for-each>
    </manifest>
</xsl:template>

Demo: http://xsltransform.hikmatu.com/jyH9rLY

Upvotes: 1

Related Questions