{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE ViewPatterns #-}
-- |
-- XML Schema Datatypes
--
-- <http://www.w3.org/TR/2004/REC-xmlschema-2-20041028/> (selected portions)
module SAML2.XML.Schema.Datatypes where

import Prelude hiding (String)

import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Base64 as B64
import Data.Char (isDigit)
import Data.Char.Properties.XMLCharProps (isXmlSpaceChar, isXmlNameChar)
import Data.Fixed (Pico, showFixed)
import Data.List (elemIndex)
import Data.Semigroup ((<>))
import qualified Data.Time.Clock as Time
import Data.Time.Format (formatTime, parseTimeM, defaultTimeLocale)
import Data.Word (Word16)
import qualified Network.URI as URI
import qualified Text.XML.HXT.Arrow.Pickle.Schema as XPS
import Text.XML.HXT.DOM.QualifiedName (isNCName)
import qualified Text.XML.HXT.DOM.XmlNode as XN
import qualified Text.XML.HXT.XMLSchema.DataTypeLibW3CNames as XSD

import qualified Text.XML.HXT.Arrow.Pickle.Xml.Invertible as XP

-- |§3.2.1
type String = [Char]

xpString :: XP.PU String
xpString :: PU String
xpString = Schema -> PU String
XP.xpTextDT (String -> Attributes -> Schema
XPS.scDTxsd String
XSD.xsd_string [])

-- |§3.2.1
type Boolean = Bool

xpBoolean :: XP.PU Boolean
xpBoolean :: PU Boolean
xpBoolean = (String -> Either String Boolean, Boolean -> String)
-> PU String -> PU Boolean
forall a b. (a -> Either String b, b -> a) -> PU a -> PU b
XP.xpWrapEither
  ( \String
s -> case String
s of
      String
"true" -> Boolean -> Either String Boolean
forall a b. b -> Either a b
Right Boolean
True
      String
"false" -> Boolean -> Either String Boolean
forall a b. b -> Either a b
Right Boolean
False
      String
"1" -> Boolean -> Either String Boolean
forall a b. b -> Either a b
Right Boolean
True
      String
"0" -> Boolean -> Either String Boolean
forall a b. b -> Either a b
Right Boolean
False
      String
_ -> String -> Either String Boolean
forall a b. a -> Either a b
Left String
"invalid boolean"
  , \Boolean
b -> if Boolean
b then String
"true" else String
"false"
  ) (PU String -> PU Boolean) -> PU String -> PU Boolean
forall a b. (a -> b) -> a -> b
$ Schema -> PU String
XP.xpTextDT (Schema -> PU String) -> Schema -> PU String
forall a b. (a -> b) -> a -> b
$ String -> Attributes -> Schema
XPS.scDTxsd String
XSD.xsd_boolean []

-- |§3.2.6 specifies a complete ISO8601 6-component duration; for SAML2 purposes we don't overly care
type Duration = Time.NominalDiffTime

xpDuration :: XP.PU Duration
xpDuration :: PU Duration
xpDuration = (String -> Either String Duration, Duration -> String)
-> PU String -> PU Duration
forall a b. (a -> Either String b, b -> a) -> PU a -> PU b
XP.xpWrapEither
  ( Either String Duration
-> (Pico -> Either String Duration)
-> Maybe Pico
-> Either String Duration
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> Either String Duration
forall a b. a -> Either a b
Left String
"invalid duration") (Duration -> Either String Duration
forall a b. b -> Either a b
Right (Duration -> Either String Duration)
-> (Pico -> Duration) -> Pico -> Either String Duration
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Pico -> Duration
forall a b. (Real a, Fractional b) => a -> b
realToFrac) (Maybe Pico -> Either String Duration)
-> (String -> Maybe Pico) -> String -> Either String Duration
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Maybe Pico
prd
  , \Duration
t -> (if Duration -> Duration
forall a. Num a => a -> a
signum Duration
t Duration -> Duration -> Boolean
forall a. Ord a => a -> a -> Boolean
< Duration
0 then (Char
'-'Char -> String -> String
forall a. a -> [a] -> [a]
:) else String -> String
forall a. a -> a
id)
    (String -> String) -> String -> String
forall a b. (a -> b) -> a -> b
$ Char
'P'Char -> String -> String
forall a. a -> [a] -> [a]
:Char
'T'Char -> String -> String
forall a. a -> [a] -> [a]
: Boolean -> Pico -> String
forall k (a :: k). HasResolution a => Boolean -> Fixed a -> String
showFixed Boolean
True (Pico -> Pico
forall a. Num a => a -> a
abs (Pico -> Pico) -> Pico -> Pico
forall a b. (a -> b) -> a -> b
$ Duration -> Pico
forall a b. (Real a, Fractional b) => a -> b
realToFrac Duration
t :: Pico) String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"S"
  ) (PU String -> PU Duration) -> PU String -> PU Duration
forall a b. (a -> b) -> a -> b
$ Schema -> PU String
XP.xpTextDT (Schema -> PU String) -> Schema -> PU String
forall a b. (a -> b) -> a -> b
$ String -> Attributes -> Schema
XPS.scDTxsd String
XSD.xsd_duration [] where
  prd :: String -> Maybe Pico
prd (Char
'-':String
s) = Pico -> Pico
forall a. Num a => a -> a
negate (Pico -> Pico) -> Maybe Pico -> Maybe Pico
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> Maybe Pico
prp String
s
  prd (Char
'+':String
s) = String -> Maybe Pico
prp String
s
  prd String
s = String -> Maybe Pico
prp String
s
  prp :: String -> Maybe Pico
prp (Char
'P':String
s) = Pico
-> (Pico -> String -> Maybe Pico)
-> [(Char, Pico)]
-> String
-> Maybe Pico
forall t p.
(Num t, Read t) =>
t -> (t -> String -> p) -> [(Char, t)] -> String -> p
pru (Pico
0 :: Pico) Pico -> String -> Maybe Pico
forall a. (Num a, Read a) => a -> String -> Maybe a
prt [(Char
'Y',Pico
31556952),(Char
'M',Pico
2629746),(Char
'D',Pico
86400)] String
s
  prp String
_ = Maybe Pico
forall a. Maybe a
Nothing
  prt :: a -> String -> Maybe a
prt a
x String
"" = a -> Maybe a
forall a. a -> Maybe a
Just a
x
  prt a
x (Char
'T':String
s) = a -> (a -> String -> Maybe a) -> [(Char, a)] -> String -> Maybe a
forall t p.
(Num t, Read t) =>
t -> (t -> String -> p) -> [(Char, t)] -> String -> p
pru a
x a -> String -> Maybe a
forall a. (Num a, Read a) => a -> String -> Maybe a
prs [(Char
'H',a
3600),(Char
'M',a
60)] String
s
  prt a
_ String
_ = Maybe a
forall a. Maybe a
Nothing
  prs :: a -> String -> Maybe a
prs a
x String
"" = a -> Maybe a
forall a. a -> Maybe a
Just a
x
  prs a
x String
s = case (Char -> Boolean) -> String -> (String, String)
forall a. (a -> Boolean) -> [a] -> ([a], [a])
span Char -> Boolean
isDigit String
s of
    (d :: String
d@(Char
_:String
_),Char
'.':((Char -> Boolean) -> String -> (String, String)
forall a. (a -> Boolean) -> [a] -> ([a], [a])
span Char -> Boolean
isDigit -> (String
p,String
"S"))) -> a -> Maybe a
forall a. a -> Maybe a
Just (a -> Maybe a) -> a -> Maybe a
forall a b. (a -> b) -> a -> b
$ a
x a -> a -> a
forall a. Num a => a -> a -> a
+ String -> a
forall a. Read a => String -> a
read (String
d String -> String -> String
forall a. [a] -> [a] -> [a]
++ Char
'.' Char -> String -> String
forall a. a -> [a] -> [a]
: String
p)
    (d :: String
d@(Char
_:String
_),String
"S") -> a -> Maybe a
forall a. a -> Maybe a
Just (a -> Maybe a) -> a -> Maybe a
forall a b. (a -> b) -> a -> b
$ a
x a -> a -> a
forall a. Num a => a -> a -> a
+ String -> a
forall a. Read a => String -> a
read String
d
    (String, String)
_ -> Maybe a
forall a. Maybe a
Nothing
  pru :: t -> (t -> String -> p) -> [(Char, t)] -> String -> p
pru t
x t -> String -> p
c [(Char, t)]
ul String
s = case (Char -> Boolean) -> String -> (String, String)
forall a. (a -> Boolean) -> [a] -> ([a], [a])
span Char -> Boolean
isDigit String
s of
    (d :: String
d@(Char
_:String
_),Char
uc:String
sr) | (Char
_,t
uv):[(Char, t)]
ur <- ((Char, t) -> Boolean) -> [(Char, t)] -> [(Char, t)]
forall a. (a -> Boolean) -> [a] -> [a]
dropWhile ((Char
uc Char -> Char -> Boolean
forall a. Eq a => a -> a -> Boolean
/=) (Char -> Boolean) -> ((Char, t) -> Char) -> (Char, t) -> Boolean
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char, t) -> Char
forall a b. (a, b) -> a
fst) [(Char, t)]
ul -> t -> (t -> String -> p) -> [(Char, t)] -> String -> p
pru (t
x t -> t -> t
forall a. Num a => a -> a -> a
+ t
uv t -> t -> t
forall a. Num a => a -> a -> a
* String -> t
forall a. Read a => String -> a
read String
d) t -> String -> p
c [(Char, t)]
ur String
sr
    (String, String)
_ -> t -> String -> p
c t
x String
s

-- |§3.2.7 theoretically allows timezones, but SAML2 does not use them
type DateTime = Time.UTCTime

xpDateTime :: XP.PU DateTime
xpDateTime :: PU DateTime
xpDateTime = PU :: forall a. Pickler a -> Unpickler a -> Schema -> PU a
XP.PU
  { theSchema :: Schema
XP.theSchema = String -> Attributes -> Schema
XPS.scDTxsd String
XSD.xsd_dateTime []
  , appPickle :: Pickler DateTime
XP.appPickle = XmlTree -> St -> St
XP.putCont (XmlTree -> St -> St) -> (DateTime -> XmlTree) -> Pickler DateTime
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> XmlTree
forall a. XmlNode a => String -> a
XN.mkText (String -> XmlTree) -> (DateTime -> String) -> DateTime -> XmlTree
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
tweakTimeString (String -> String) -> (DateTime -> String) -> DateTime -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. TimeLocale -> String -> DateTime -> String
forall t. FormatTime t => TimeLocale -> String -> t -> String
formatTime TimeLocale
defaultTimeLocale String
fmtz
  , appUnPickle :: Unpickler DateTime
XP.appUnPickle = Unpickler XmlTree
XP.getCont Unpickler XmlTree
-> (XmlTree -> Unpickler String) -> Unpickler String
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= String -> Maybe String -> Unpickler String
forall a. String -> Maybe a -> Unpickler a
XP.liftMaybe String
"dateTime expects text" (Maybe String -> Unpickler String)
-> (XmlTree -> Maybe String) -> XmlTree -> Unpickler String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. XmlTree -> Maybe String
forall a. XmlNode a => a -> Maybe String
XN.getText Unpickler String
-> (String -> Unpickler DateTime) -> Unpickler DateTime
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= String -> Unpickler DateTime
forall a. ParseTime a => String -> Unpickler a
parseTime
  }
  where
  -- timezone must be 'Z', and MicrosoftS(tm) Azure(tm) will choke when it is ommitted.  (error
  -- messages are utterly unhelpful.)
  fmtz :: String
fmtz = String
"%Y-%m-%dT%H:%M:%S%QZ"

  parseTime :: String -> Unpickler a
parseTime String
dateString = Unpickler a -> (a -> Unpickler a) -> Maybe a -> Unpickler a
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> Unpickler a
forall a. String -> Unpickler a
XP.throwMsg (String -> Unpickler a) -> String -> Unpickler a
forall a b. (a -> b) -> a -> b
$ String
"can't parse date " String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
dateString) a -> Unpickler a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
    (Maybe a -> Unpickler a) -> Maybe a -> Unpickler a
forall a b. (a -> b) -> a -> b
$ Boolean -> TimeLocale -> String -> String -> Maybe a
forall (m :: * -> *) t.
(MonadFail m, ParseTime t) =>
Boolean -> TimeLocale -> String -> String -> m t
parseTimeM Boolean
True TimeLocale
defaultTimeLocale String
fmtz String
dateString

  -- adding '%Q' may be longer than 7 digits, which makes MicrosoftS(tm) Azure(tm) choke.
  tweakTimeString :: String -> String
  tweakTimeString :: String -> String
tweakTimeString String
s = case Char -> String -> Maybe Int
forall a. Eq a => a -> [a] -> Maybe Int
elemIndex Char
'.' String
s of
    Maybe Int
Nothing -> String
s
    Just Int
i -> case Int -> String -> (String, String)
forall a. Int -> [a] -> ([a], [a])
splitAt Int
i String
s of
      (String
t, String
u) -> case Int -> String -> (String, String)
forall a. Int -> [a] -> ([a], [a])
splitAt Int
8 String
u of
        (String
_, String
"") -> String
t String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
u
        (String
v, String
_)  -> String
t String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
v String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"Z"

-- |§3.2.16
type Base64Binary = BS.ByteString

xpBase64Binary :: XP.PU Base64Binary
xpBase64Binary :: PU Base64Binary
xpBase64Binary = (String -> Either String Base64Binary, Base64Binary -> String)
-> PU String -> PU Base64Binary
forall a b. (a -> Either String b, b -> a) -> PU a -> PU b
XP.xpWrapEither
  ( Base64Binary -> Either String Base64Binary
B64.decode (Base64Binary -> Either String Base64Binary)
-> (String -> Base64Binary) -> String -> Either String Base64Binary
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Base64Binary
BS.pack (String -> Base64Binary)
-> (String -> String) -> String -> Base64Binary
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Boolean) -> String -> String
forall a. (a -> Boolean) -> [a] -> [a]
filter (Boolean -> Boolean
not (Boolean -> Boolean) -> (Char -> Boolean) -> Char -> Boolean
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Boolean
isXmlSpaceChar)
  , Base64Binary -> String
BS.unpack (Base64Binary -> String)
-> (Base64Binary -> Base64Binary) -> Base64Binary -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Base64Binary -> Base64Binary
B64.encode
  ) (PU String -> PU Base64Binary) -> PU String -> PU Base64Binary
forall a b. (a -> b) -> a -> b
$ Schema -> PU String
XP.xpText0DT (Schema -> PU String) -> Schema -> PU String
forall a b. (a -> b) -> a -> b
$ String -> Attributes -> Schema
XPS.scDTxsd String
XSD.xsd_base64Binary []

-- |§3.2.17
type AnyURI = URI.URI

xpAnyURI :: XP.PU AnyURI
xpAnyURI :: PU AnyURI
xpAnyURI = (String -> Either String AnyURI, AnyURI -> String)
-> PU String -> PU AnyURI
forall a b. (a -> Either String b, b -> a) -> PU a -> PU b
XP.xpWrapEither
  ( Either String AnyURI
-> (AnyURI -> Either String AnyURI)
-> Maybe AnyURI
-> Either String AnyURI
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (String -> Either String AnyURI
forall a b. a -> Either a b
Left String
"invalid anyURI") AnyURI -> Either String AnyURI
forall a b. b -> Either a b
Right (Maybe AnyURI -> Either String AnyURI)
-> (String -> Maybe AnyURI) -> String -> Either String AnyURI
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Maybe AnyURI
URI.parseURIReference
  , \AnyURI
u -> (String -> String) -> AnyURI -> String -> String
URI.uriToString String -> String
forall a. a -> a
id AnyURI
u String
"")
  (PU String -> PU AnyURI) -> PU String -> PU AnyURI
forall a b. (a -> b) -> a -> b
$ Schema -> PU String
XP.xpText0DT (Schema -> PU String) -> Schema -> PU String
forall a b. (a -> b) -> a -> b
$ String -> Attributes -> Schema
XPS.scDTxsd String
XSD.xsd_anyURI []

-- |§3.3.1
type NormalizedString = String
-- |§3.3.2
type Token = NormalizedString
-- |§3.3.3
type Language = Token

xpLanguage :: XP.PU Language
xpLanguage :: PU String
xpLanguage = Schema -> PU String
XP.xpTextDT (Schema -> PU String) -> Schema -> PU String
forall a b. (a -> b) -> a -> b
$ String -> Attributes -> Schema
XPS.scDTxsd String
XSD.xsd_language []

-- |§3.3.4
type NMTOKEN = Token

isNMTOKEN :: Token -> Bool
isNMTOKEN :: String -> Boolean
isNMTOKEN [] = Boolean
False
isNMTOKEN String
s = (Char -> Boolean) -> String -> Boolean
forall (t :: * -> *) a.
Foldable t =>
(a -> Boolean) -> t a -> Boolean
all Char -> Boolean
isXmlNameChar String
s

xpNMTOKEN :: XP.PU NMTOKEN
xpNMTOKEN :: PU String
xpNMTOKEN = (String -> Either String String, String -> String)
-> PU String -> PU String
forall a b. (a -> Either String b, b -> a) -> PU a -> PU b
XP.xpWrapEither
  ( \String
x -> if String -> Boolean
isNMTOKEN String
x then String -> Either String String
forall a b. b -> Either a b
Right String
x else String -> Either String String
forall a b. a -> Either a b
Left String
"NMTOKEN expected"
  , String -> String
forall a. a -> a
id
  ) (PU String -> PU String) -> PU String -> PU String
forall a b. (a -> b) -> a -> b
$ Schema -> PU String
XP.xpTextDT (Schema -> PU String) -> Schema -> PU String
forall a b. (a -> b) -> a -> b
$ String -> Attributes -> Schema
XPS.scDTxsd String
XSD.xsd_NMTOKEN []

-- |§3.3.5
type NMTOKENS = [NMTOKEN]

xpNMTOKENS :: XP.PU NMTOKENS
xpNMTOKENS :: PU NMTOKENS
xpNMTOKENS = (String -> Either String NMTOKENS, NMTOKENS -> String)
-> PU String -> PU NMTOKENS
forall a b. (a -> Either String b, b -> a) -> PU a -> PU b
XP.xpWrapEither
  ( \String
x -> case String -> NMTOKENS
words String
x of
      [] -> String -> Either String NMTOKENS
forall a b. a -> Either a b
Left String
"NMTOKENS expected"
      NMTOKENS
l | (String -> Boolean) -> NMTOKENS -> Boolean
forall (t :: * -> *) a.
Foldable t =>
(a -> Boolean) -> t a -> Boolean
all String -> Boolean
isNMTOKEN NMTOKENS
l -> NMTOKENS -> Either String NMTOKENS
forall a b. b -> Either a b
Right NMTOKENS
l
      NMTOKENS
_ -> String -> Either String NMTOKENS
forall a b. a -> Either a b
Left String
"NMTOKENS expected"
  , NMTOKENS -> String
unwords
  ) (PU String -> PU NMTOKENS) -> PU String -> PU NMTOKENS
forall a b. (a -> b) -> a -> b
$ Schema -> PU String
XP.xpTextDT (Schema -> PU String) -> Schema -> PU String
forall a b. (a -> b) -> a -> b
$ String -> Attributes -> Schema
XPS.scDTxsd String
XSD.xsd_NMTOKENS []

-- |§3.3.8
type ID = String
type NCName = String

xpNCName :: XP.PU NCName
xpNCName :: PU String
xpNCName = (String -> Either String String, String -> String)
-> PU String -> PU String
forall a b. (a -> Either String b, b -> a) -> PU a -> PU b
XP.xpWrapEither
  ( \String
x -> if String -> Boolean
isNCName String
x then String -> Either String String
forall a b. b -> Either a b
Right String
x else String -> Either String String
forall a b. a -> Either a b
Left String
"NCName expected"
  , String -> String
forall a. a -> a
id
  ) (PU String -> PU String) -> PU String -> PU String
forall a b. (a -> b) -> a -> b
$ Schema -> PU String
XP.xpTextDT (Schema -> PU String) -> Schema -> PU String
forall a b. (a -> b) -> a -> b
$ String -> Attributes -> Schema
XPS.scDTxsd String
XSD.xsd_NCName []

xpID :: XP.PU ID
xpID :: PU String
xpID = PU String
xpNCName{ theSchema :: Schema
XP.theSchema = String -> Attributes -> Schema
XPS.scDTxsd String
XSD.xsd_ID [] }

-- |§3.3.13
xpInteger :: XP.PU Integer
xpInteger :: PU Integer
xpInteger = PU Integer
forall a. (Read a, Show a) => PU a
XP.xpPrim{ theSchema :: Schema
XP.theSchema = String -> Attributes -> Schema
XPS.scDTxsd String
XSD.xsd_integer [] }

-- |§3.3.20
type NonNegativeInteger = Word

xpNonNegativeInteger :: XP.PU NonNegativeInteger
xpNonNegativeInteger :: PU NonNegativeInteger
xpNonNegativeInteger = PU NonNegativeInteger
forall a. (Read a, Show a) => PU a
XP.xpPrim{ theSchema :: Schema
XP.theSchema = String -> Attributes -> Schema
XPS.scDTxsd String
XSD.xsd_nonNegativeInteger [] }

-- |§3.3.23
type UnsignedShort = Word16

xpUnsignedShort :: XP.PU UnsignedShort
xpUnsignedShort :: PU UnsignedShort
xpUnsignedShort = PU UnsignedShort
forall a. (Read a, Show a) => PU a
XP.xpPrim{ theSchema :: Schema
XP.theSchema = String -> Attributes -> Schema
XPS.scDTxsd String
XSD.xsd_unsignedShort [] }

-- |§3.3.20
type PositiveInteger = NonNegativeInteger

xpPositiveInteger :: XP.PU PositiveInteger
xpPositiveInteger :: PU NonNegativeInteger
xpPositiveInteger = (NonNegativeInteger -> Either String NonNegativeInteger,
 NonNegativeInteger -> NonNegativeInteger)
-> PU NonNegativeInteger -> PU NonNegativeInteger
forall a b. (a -> Either String b, b -> a) -> PU a -> PU b
XP.xpWrapEither
  ( \NonNegativeInteger
x -> if NonNegativeInteger
x NonNegativeInteger -> NonNegativeInteger -> Boolean
forall a. Ord a => a -> a -> Boolean
> NonNegativeInteger
0 then NonNegativeInteger -> Either String NonNegativeInteger
forall a b. b -> Either a b
Right NonNegativeInteger
x else String -> Either String NonNegativeInteger
forall a b. a -> Either a b
Left String
"0 is not positive"
  , NonNegativeInteger -> NonNegativeInteger
forall a. a -> a
id
  ) (PU NonNegativeInteger -> PU NonNegativeInteger)
-> PU NonNegativeInteger -> PU NonNegativeInteger
forall a b. (a -> b) -> a -> b
$ PU NonNegativeInteger
forall a. (Read a, Show a) => PU a
XP.xpPrim{ theSchema :: Schema
XP.theSchema = String -> Attributes -> Schema
XPS.scDTxsd String
XSD.xsd_positiveInteger [] }