Substring before throwing error

546 views Asked by At

I've the below XML

<?xml version="1.0" encoding="UTF-8"?>
<body>
 <p>Industrial drawing: Any creative composition</p>
   <p>Industrial drawing: Any creative<fn>
          <fnn>4</fnn>
          <fnt>
            <p>ftn1"</p>
          </fnt>
        </fn> composition
      </p>
</body>

and the below XSL.

<xsl:template match="p">
    <xsl:choose>
        <xsl:when test="contains(substring-before(./text(),' '),'Article')">
            <xsl:text>sect3</xsl:text>
            <xsl:value-of select="./text()"/>
        </xsl:when>
        <xsl:when test="contains(substring-before(./b/text(),' '),'Section')">
            <xsl:text> Sect 2</xsl:text>
            <xsl:value-of select="./text()"/>
        </xsl:when>
        <xsl:when test="contains(substring-before(./b/text(),' '),'Chapter')">
            <xsl:text> Sect 1</xsl:text>
            <xsl:value-of select="./text()"/>
        </xsl:when>
        <xsl:otherwise>

</xsl:otherwise>
    </xsl:choose>
</xsl:template>

Here my XSL is working fine for <p>Industrial drawing: Any creative composition</p> but for the below Case

 <p>Industrial drawing: Any creative<fn>
      <fnn>4</fnn>
         <fnt>
            <p>ftn1"</p>
         </fnt>
      </fn> composition
 </p>

it is throwing me the below error.

XSLT 2.0 Debugging Error: Error: file:///C:/Users/u0138039/Desktop/Proview/ASAK/DIFC/XSLT/tabel.xslt:38: Wrong occurrence to match required sequence type -   Details: -     XPTY0004: The supplied sequence ('2' item(s)) has the wrong occurrence to match the sequence type xs:string ('zero or one')

please let me know how can i fix this and grab the text required.

Thanks

2

There are 2 answers

0
michael.hor257k On BEST ANSWER

The p element in your example has several text nodes, so the expression ./text() creates a sequence. You cannot apply a string function to a sequence; you must convert it to a string first. Instead of:

test="contains(substring-before(./text(),' '),'Article')"

try:

test="contains(substring-before(string-join(text(), ''), ' '), 'Article')"
0
Ian Roberts On

The second p element in your example XML has two child text nodes, one containing "Industrial drawing: Any creative" and the other containing a space, "composition", a newline and another six spaces. In XSLT 1.0 it is legal to apply a function that expects a string to an argument that is a set of more than one node, the behaviour is to take the value of the first node and ignore all the others. But in 2.0 it is a type mismatch error to pass two nodes to a function that expected a single value for its parameter.

But in this case I doubt that you really need to use text() at all - if all you care about is seeing whether the string "Article" occurs anywhere within the first word under the p (including when this is nested inside another element) then you can simply use .:

<xsl:when test="contains(substring-before(.,' '),'Article')">

(or better still, use predicates to separate the different conditions into their own templates, with one template matching "Article" paragraphs, another matching "Section" paragraphs, etc.)