3

I have the following XML Schema:

CREATE XML SCHEMA COLLECTION test AS '
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <xsd:element name="PointConf">
    <xsd:complexType>
          <xsd:sequence>
            <xsd:element name="GlobalFlags">
              <xsd:complexType>
                    <xsd:sequence>
                      <xsd:element name="Order" type="OrderType"/>
                      <xsd:any processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
                    </xsd:sequence>
              </xsd:complexType>  
            </xsd:element>           
          </xsd:sequence>
    </xsd:complexType>
  </xsd:element>

  <xsd:complexType name="OrderType">
    <xsd:attribute name="value" type="xsd:int" />
  </xsd:complexType>
</xsd:schema>
'
GO

Then I use it in this way:

DECLARE @xml xml(test)

SET @xml='<PointConf>
  <GlobalFlags>    
    <Order value="1" />
  </GlobalFlags>

</PointConf>'

SELECT @xml.value('(/PointConf/GlobalFlags/Order/@value)[1]','int')

SELECT gives me the following error:

XQuery [value()]: 'value()' requires a singleton (or empty sequence), found operand of type '(xs:int | xdt:anyAtomicType *) ?'

Without the xsd:any element in the schema the code above works without any errors. What am I doing wrong?

Kirill V. Lyadvinsky
  • 97,037
  • 24
  • 136
  • 212

1 Answers1

2

I got the select to work by using the statement

SELECT @xml.value('string(/PointConf[1]/GlobalFlags/Order[1]/@value)','int')

I understand the requirement for the [1] index on the Order node, as this can be a list, however I don't see why its required for the PointConf node.

The [1] needs to be used at the actual level where a list exists to restrict that list to a single return value

The string(...) turns the node set into a string (or empty string). I think this helps with the xsd:any although I'm not completely sure why - something to do with handling the possibility of the node Order being missing completely I think.


Update:

Investigating further:

SELECT @xml.value('string((/PointConf/GlobalFlags/Order/@value)[1])','int')

also works.

So its just the string function that's required to make it work in this instance.

Jon Egerton
  • 40,401
  • 11
  • 97
  • 129
  • Isn't `(/PointConf/GlobalFlags/Order/@value)[1]` already gives me only one value from the resulting set? What the reason for using `string`? – Kirill V. Lyadvinsky Sep 01 '11 at 09:42
  • On testing more, you can use that xpath inside the string function to make it work. As I said in my original answer, I'm not completely sure about why `string()` works, but I think its something to do with turning a fail into an empty string. – Jon Egerton Sep 01 '11 at 09:54