confusing error thown while trying to match templa

2019-09-14 19:28发布

问题:

I've the below XML line of code.

<entry colname="col3" align="left" valign="top"><para>grandchild, cousin, <content-style font-style="italic">etc</content-style>., shall be described as “lawful” and “one of the next-of-kin” or “only next-of-kin”.</para></entry>

and below XSL

<xsl:template match="entry" name="entry">
  <xsl:choose>
    <xsl:when test="./@namest">
      <xsl:variable name="namest" select="@namest" />
      <xsl:variable name="nameend" select="@nameend" />
      <xsl:variable name="namestPos" select="count(ancestor::tgroup/colspec[@colname=$namest]/preceding-sibling::colspec)" />
      <xsl:variable name="nameendPos" select="count(ancestor::tgroup/colspec[@colname=$nameend]/preceding-sibling::colspec)" />
      <td colspan="{$nameendPos - $namestPos + 1}" align="{@align}">
        <xsl:apply-templates select="child::node()[not(self::page)]" />
      </td>
    </xsl:when>
    <xsl:otherwise>
      <td>
        <xsl:if test="./@morerows">
          <xsl:attribute name="rowspan">
            <xsl:value-of select="number(./@morerows)+1" />
          </xsl:attribute>
        </xsl:if>
        <xsl:if test="./@align">
          <xsl:attribute name="align">
            <xsl:value-of select="@align" />
          </xsl:attribute>
        </xsl:if>
        <xsl:if test="./@valign">
          <xsl:attribute name="valign">
            <xsl:value-of select="@valign" />
          </xsl:attribute>
        </xsl:if>
        <xsl:for-each select="para">
          <div class="para">
            <xsl:choose>
              <xsl:when test="../@colname='col3' and contains(./text(),'.')">
                <xsl:variable name="strl">
                  <xsl:value-of select="fn:string-length(fn:substring-before(.,'.'))" />
                </xsl:variable>
                <xsl:choose>
                  <xsl:when test="$strl &lt; '6'">
                    <a href="{concat('er:#SCP_ORD_',//chapter/@num,'/','P',translate(./text(),'.','-'))}">
                      <xsl:value-of select="./text()" />
                    </a>
                  </xsl:when>
                  <xsl:otherwise>
                    <xsl:apply-templates />
                  </xsl:otherwise>
                </xsl:choose>
              </xsl:when>
              <xsl:otherwise>
                <xsl:apply-templates />
              </xsl:otherwise>
            </xsl:choose>
          </div>
        </xsl:for-each>
      </td>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

and when i run this on my XML in the above mentioned line(the XML given in the sample), it is throwing me an error. and the error is as below.

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')

here what i actually was trying to achieve is, i have another table(which is basically a TOC), where in there is some linking needed, and below is such sample entries.

<entry colname="col3" align="right" valign="top"><para>A.1</para></entry>
<entry colname="col3" align="right" valign="top"><para>A.2</para></entry>

here i'm searching if the colname is col3 and if this has a . in it, and the above two cases mentioned are passing and are getting linked successfully, where in the case mentioned in the top is throwing the error, can anyone please suggest some better method to differentiate these two cases, and i use XSLT 2.0.

Thanks

回答1:

The problem is

contains(./text(),'.')

./text() is not "the text of the current element" but rather the sequence of all text node children of the current element. In the case of

<para>grandchild, cousin, <content-style font-style="italic">etc</content-style>., shall be described as “lawful” and “one of the next-of-kin” or “only next-of-kin”.</para>

there are two such nodes, one containing everything between the <para> and <content-style> tags ("grandchild, cousin, " including the trailing space) and the other containing everything between the </content-style> and the </para>. But the contains function expects its first argument to be a single string, not a sequence of two nodes.

Instead of testing ./text() you probably just need to test .:

contains(., '.')

which is interpreted as the string value of the whole para element, i.e. a single string consisting of the concatenation of all the descendant text nodes (so the whole text "grandchild, cousin, etc., shall be described...").



标签: xslt