1
votes

I have this structure in XML:

<report>
  <text>
    <chapter>1</chapter>
    <chapter>2
        <section>2.1</section>
    </chapter>
    <chapter>3</chapter>
  </text>
</report>

In my DTD, I have:

 <!ELEMENT text (#PCDATA | chapter |section)*>

Because of this, in my XSL, i want the garantee that I don't have a chapter and a section in the same level, before doing the transformation. So, i can't have this

<report>
  <text>
    <chapter>1</chapter>
    <chapter>2
        <section>2.1</section>
    </chapter>
    <section>3</section>
  </text>
</report>

My XSL

<xsl:template match="chapter">

    <div class="chapter">   
        <h2> 
            <xsl:apply-templates select="chapter-title"/>
        </h2>       
        <hr/>
        <xsl:apply-templates select="text() | section "/>
    </div>
</xsl:template> 
<xsl:template match="section">
    <div class="section">
        <h3>  
            <xsl:apply-templates select="section-title"/>
        </h3>
        <xsl:apply-templates select="text()"/>
    </div>
</xsl:template>

How can I check if a section and a chapter are at the same level, in XSL? Thanks.

3
You want to validate or you want xml to transform into expected xml format? - Mind Peace
I want to validate. I just transform a section if it is not at the same level of a chapter. @MindPeace i just edited my post with my current XSL. - CatCos

3 Answers

1
votes

Following XSLT produces true as its output if chapter and section are at the same level, else nothing:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="text" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="*">
    <xsl:choose>
        <xsl:when test="chapter and section">true</xsl:when>
        <xsl:otherwise>
            <xsl:apply-templates select="*"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>
</xsl:stylesheet>
0
votes

Use the XPath axes, parent should work in this case:

<xsl:if test="count(parent::*/*) &gt; 0">...</xsl:if>

Select the parent node: parent::*

Select all elements nodes inside the parent node: parent::*/*

Count them and check here are more then zero: count(parent::*/*) > 0

* will return any element node, but not text node. You can use the element node name to select specific element nodes.

0
votes

You need xsl:message:

<xsl:template match="*[chapter][section]">
    <xsl:message terminate="yes">There are a section and a chapter on the same level</xsl:message>
</xsl:template>

terminate="yes" skips the process, if the processor comes to this message. If you just need a warning, switch to "no".

Maybe Schematron is interessting for you. In this case you would need:

<schema xmlns="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2">
    <pattern>
        <rule context="*[chapter]">
            <report test="section">There are a section and a chapter on the same level</report>
        </rule>
    </pattern>
</schema>