.packageName <- "StatDataML"
handlersSDML <- function() {
  list(
       textdata = function(x, ...) {
         
         sep <- ifelse("sep" %in% names(xmlAttrs(x)),
                       xmlAttrs(x)["sep"], " \n\r")
         sep <- paste("[", sep, "]+", sep="")
         
         type <- ifelse("type" %in% names(xmlAttrs(x)),
           xmlAttrs(x)["type"], "character")
         mode <- NULL
         if ("mode" %in% names(xmlAttrs(x)))
           mode <- as.character(xmlAttrs(x)["mode"])
         posinf <- ifelse("posinf.string" %in% names(xmlAttrs(x)),
           xmlAttrs(x)["posinf.string"], "+Inf")
         neginf <- ifelse("neginf.string" %in% names(xmlAttrs(x)),
           xmlAttrs(x)["neginf.string"],"-Inf")
         nan <- ifelse("nan.string" %in% names(xmlAttrs(x)),
           xmlAttrs(x)["nan.string"], "NaN")
         na <- ifelse("na.string" %in% names(xmlAttrs(x)),
           xmlAttrs(x)["na.string"], "NA")
         null <- ifelse("null.string" %in% names(xmlAttrs(x)),
           xmlAttrs(x)["null.string"], "NULL")
         true <- ifelse("true" %in% names(xmlAttrs(x)),
           xmlAttrs(x)["true"], "1")
         false <- ifelse("false" %in% names(xmlAttrs(x)),
           xmlAttrs(x)["false"], "0")
         
         children <- if(is.null(x[[1]]))
           NULL
         else
           list(unlist(strsplit(xmlValue(x[[1]]), sep)))
         
         structure(list(children = children,
                        name = "textdata",
                        attributes = c(
                          type = type,
                          mode = mode,
                          posinf.string = posinf,
                          neginf.string = neginf,
                          nan.string = nan,
                          na.string = na,
                          null.string = null,
                          true = true,
                          false = false
                         )
                        ),
                   class = "XMLNode"
                   )
       })
}

readArraySDML <- function(x)
{
  if (is.null(x)) return(NULL)
    
  ## parse dimension
  dimension <- readDimensionSDML(x[["dimension"]])

  ## parse categories
  type <- readType(x[["type"]])
  
  ## parse properties
  attrib <- readProperties(x[["properties"]])

  info <- NULL

  if (!is.null(x[["data"]]) || !is.null(x[["textdata"]])) {
    
    if(!is.null(x[["data"]])) {
      attribs <- getAttrSDML(x[["data"]])
      vals <- if (!is.null(type$type) && type$type == "numeric" && type$mode == "complex")
        getComplexDataSDML(xmlChildren(x[["data"]]))
      else
        getDataSDML(xmlChildren(x[["data"]]))
      info <- attr(vals, "info")
    } else {
      attribs <- getAttrSDML(x[["textdata"]])
      vals <- if (is.null(xmlChildren(x[["textdata"]])))
        character()
      else
        getTextDataSDML(xmlChildren(x[["textdata"]])[[1]], attribs, type$type)
    }

    if (length(vals) != prod(dimension$dim))
      stop(paste("Wrong dimension !", paste(dimension$dim, collapse=", "), length(vals), collapse= " "))
    
    if (length(dimension$dim) > 1) {
      vals <- array(vals, dim=dimension$dim, dimnames=dimension$names)
      if (!is.null(x[["data"]])) {
        if (!is.null(info))
          info <- array(info, dim=dimension$dim, dimnames=dimension$names)
      }
    } else {
      if (!length(vals))
        vals <- vector()
      else
        if (length(dimension$names[[1]]))
          names(vals) <- dimension$names[[1]]
    }

    ## handle types
    if (!is.null(type$type)) {
      
      if (!is.null(x[["textdata"]]) && type$type == "logical") {
        tr <- as.character(default(attribs, "true", "1"))
        fa <- as.character(default(attribs, "false", "0"))
        vals1 <- vals == tr
        vals2 <- !(vals == fa)
        vals <- vals1
        vals[vals != vals2] <- NA
      }
      
      if (type$type == "numeric") {
        if (type$mode %in% c("integer", "real", "complex"))
          mode(vals) <- type$mode
        else ## default mode if none
          mode(vals) <- "double"

        if (type$mode %in% c("integer", "real") &&
            (min(vals, na.rm=TRUE) < type$min || 
             max(vals, na.rm=TRUE) > type$max))
          warning("numeric values out of specified range.", call. = FALSE)
      }
      
      if (type$type == "categorical") {
        if (type$mode == "ordered")
          vals <- ordered(as.integer(vals), labels = type$labels)
        else
          vals <- factor(as.integer(vals), labels = type$labels)
      }
      
      if (type$type == "datetime")
        vals <- as.POSIXct(strptime(vals, format="%Y-%m-%dT%H:%M:%S"))

      if (type$type == "character")
        vals <- as.character(vals)
    }
    
    atvals <- attributes(vals)
    if (!is.null(atvals)) attrib <- c(atvals, attrib)

    ## recombine possibly splitted class attribute
    ind <- names(attrib) == "class"
    if (length(ind)) {
      newclass <- as.character(unlist(attrib[ind]))
      attrib[ind] <- NULL
      attrib[["class"]] <- newclass
    }

    if (!is.null(attrib)) attributes(vals) <- attrib
    if (!is.null(info))
      attr(vals, "info") <- info
    return(vals)
  }
}

getComplexDataSDML <- function(y) {
  ret <- as.complex(sapply(y, function(x) {
    if (x$name=="na") return(NA)
    cs <- getDataSDML(xmlChildren(x))
    complex(1, as.double(cs[1]), as.double(cs[2]))
  }))
  i <- sapply(y, function(x) if (is.null(a <- getAttrSDML(x)[["info"]])) NA else a)
  attributes(i) <- NULL
  if (!all(is.na(i))) attr(ret, "info") <- i
  ret
}

getDataSDML <- function(y) 
{
  w <- sapply(y,
              function(x) switch (x$name,
                                  na = NA,
                                  T = TRUE,
                                  F = FALSE,
                                  if (is.null(x[[1]])) "" else 
                                  switch(x[[1]]$name,
                                         posinf = +Inf,
                                         neginf = -Inf,
                                         nan    = NaN,
                                         xmlValue(x[[1]])
                                         )
                                  )
                )
    attributes(w) <- NULL

    i <- sapply(y, function(x) if (is.null(a <- getAttrSDML(x)[["info"]])) NA else a)
    attributes(i) <- NULL
    
    if(is.character(w)) {
        w <- gsub("&amp;", "&", w)
        w <- gsub("&lt;", "<", w)
        w <- gsub("&gt;", ">", w)
    }

    if (!all(is.na(i))) attr(w, "info") <- i
    w
}

getTextDataSDML <- function(y, attribs, type) 
{
  y <- gsub("&amp;", "&", y)
  y <- gsub("&lt;", "<", y)
  y <- gsub("&gt;", ">", y)
  y[y == attribs[["na.string"]]] <- NA
  if (type == "character")
    y[y == attribs[["null.string"]]] <- ""
  if (type == "numeric") {
    y <- gsub(attribs[["neginf.string"]], "-Inf", y)
    y <- gsub(attribs[["posinf.string"]], "Inf", y)
    y <- gsub(attribs[["nan.string"]], "NaN", y)
  }
  if (type == "logical") {
    y[y == attribs[["true"]]] <- "1"
    y[y == attribs[["false"]]] <- "0"
  }
  y
}

default <- function (attr, name, defval) 
  if (name %in% names(attr)) attr[name] else defval




readDatasetSDML <- function(x)
{
  if(is.null(x)) return(NULL)
  
  ## a dataset contains either a list or an array 
  if(!is.null(x[["list"]]))
    return(readListSDML(x[["list"]]))
    
  if(!is.null(x[["array"]]))
    return(readArraySDML(x[["array"]]))
}
readDescriptionSDML <- function(x)
{
  if(is.null(x)) return(NULL)

  list(
       title      = xmlValue(x[["title"]]),
       source     = xmlValue(x[["source"]]),
       date       = xmlValue(x[["date"]]),
       version    = xmlValue(x[["version"]]),
       comment    = xmlValue(x[["comment"]]),
       creator    = xmlValue(x[["creator"]]),
       properties = readProperties(x[["properties"]])
       )
}
readDimensionSDML <- function(x)
{
    dim <- NULL
    dimnames <- NULL
    names <- list()
    if (xmlName(x) == "dimension") {
      if (xmlSize(x)) {
        for (k in 1:xmlSize(x)) {
          dim[k]     <- xmlAttrs(x[[k]])["size"]
          if (!is.na(xmlAttrs(x[[k]])["name"]))
              dimnames[k] <- xmlAttrs(x[[k]])["name"]
          names[[k]] <- getDataSDML(xmlChildren(x[[k]]))
        }
      } else dim <- 0
    }
    mode(dim) <- "integer"
    if (!is.null(dimnames)) names(names) <- dimnames
    list(dim=dim, names=names)
}
# used for list tags as well as for listdata tags
readListSDML <- function(x)
{
  if (is.null(x)) return(NULL)
  
  if (xmlName(x) == "list") {
    ## dimension
    dimension <- readDimensionSDML(x[["dimension"]])

    ## properties (NULL if none)
    attrib <- readProperties(x[["properties"]])

    ## fetch sublists
    thislist <- lapply(xmlChildren(x[["listdata"]]), readListSDML)
    if (!length(thislist)) return(thislist)
      
    ## set names:
    ### no names for arrays
    if(names(thislist) == "array") names(thislist) <- NULL
        
    ### list with dim attribute?
    if(length(dimension$dim) > 1) {
      dim(thislist) <- dimension$dim
      dimnames(thislist) <- dimension$names
    } else
    ### only one dimension?
      if(length(dimension$names[[1]]) > 0)
        names(thislist) <- dimension$names[[1]]
    
    ## set/append properties
    atL <- attributes(thislist)
    if (!is.null(atL)) attrib <- c(attrib, atL)
    if (!is.null(attrib)) attributes(thislist) <- attrib
    
    return(thislist)
  }
    
  if (xmlName(x) == "array")
    return(readArraySDML(x))

  if (xmlName(x) == "empty")
    return(NULL)
}
readProperties <- function(x)
{
	return(readListSDML(x[["list"]]))
}
readSDML <- function(file = "", text = NULL, validate = FALSE,
                     read.description = FALSE)
{
  tree <- xmlTreeParse(file=file, asText=!is.null(text), validate=validate,
                       handler=handlersSDML(), asTree=TRUE)

  ## is this file a StatDataML file ?    
  if (xmlName(xmlRoot(tree)) != "StatDataML")
    stop("This is no StatDataML file");

  ## get root node
  statxml <- xmlRoot(tree)
  
  ## read dataset
  dataset <- readDatasetSDML(statxml[["dataset"]])
    
  ## if requested, handle description
  if (read.description) {
    ## read it
    description <- readDescriptionSDML(statxml[["description"]])
    
    if(!is.null(description)) {
      ## if there is a description only, use an empty list as a dummy object to carry it
      if(is.null(dataset)) dataset <- list()

      ## set description as an attribute
      attr(dataset,"SDMLdescription") <- description
    }
  }
  
  return(dataset)
}
 
readType <- function(x)
{
  ret <- list()
  ret$type <- "character"
  ret$mode <- NULL
  ret$labels <- NULL
  ret$min <- -Inf
  ret$max <- +Inf
  
  if (xmlName(x) == "type") {
    x <- x[[1]]
    ret$type <- xmlName(x)

    if (ret$type == "categorical") {
      ## mode
      ret$mode <- xmlAttrs(x)["mode"]
      
      ## labels
      for (k in 1:xmlSize(x)) {
        code <- as.integer(xmlAttrs(x[[k]])["code"])
        lab <- xmlChildren(x[[k]])
        ret$labels[code] <- if (is.null(lab)) k else xmlValue(lab[[1]])
      }
    }

    if (ret$type == "numeric") {
      if (!length(xmlChildren(x)))
        ret$mode <- "real"
      else {
        x <- x[[1]]
        ret$mode <- xmlName(x)
        l <- length(xmlChildren(x))
        if (ret$mode %in% c("integer", "real") && l)
          for (i in 1:l)
            ret[[xmlName(x[[i]])]] <- getDataSDML(x[i])
      }
    }
  }

  ret
}
catSDML <- function(...) cat(..., append=TRUE, sep="")

etagsSDML <- function(x, ...)
{
  info <- attr(x, "info")
  for (i in 1:length(x)) {
    inf <- if (!is.null(info) && !is.na(info[i]))
      paste(" info=\"", info[i], "\"", sep="")
    else ""
    
    if (is.na(x[i]) && !is.nan(x[i]))
      catSDML("\<na", inf, "/>", ...)
    else
      if (is.logical(x))
        catSDML("\<", if (x[i]) "T" else "F", inf, "/>", ...)
      else
        tags(x[i], "e", inf, ...)
    
    if((i!=length(x)) & ((i %% 5)==0))
      catSDML("\n", ...)
  }
}

cetagsSDML <- function(x, ...)
{
  info <- attr(x, "info")
  for (i in 1:length(x)) {
    inf <- if (!is.null(info) && !is.na(info[i]))
      paste(" info=\"", info[i], "\"", sep="")
    else ""
    
    if (is.na(x[i]) && !is.nan(x[i]))
      catSDML("\<na",inf,"/>", ...)
    else {
      catSDML("\<ce",inf,">", ...)
      tags(Re(x[i]),"r", ...)
      tags(Im(x[i]),"i", ...)
      catSDML("\</ce>", ...)
    }
    
    if((i!=length(x)) & ((i %% 3)==0))
      catSDML("\n", ...)
  }
}

tags <- function(x, s, info = "", ...) {
  if (is.nan(x))
    catSDML("\<", s, info, "><nan/></", s, ">", ...)
  else if (x == Inf)
    catSDML("\<", s, info, "><posinf/></", s, ">", ...)
  else if (x == -Inf)
    catSDML("\<", s, info, "><neginf/></", s, ">", ...)
  else
    catSDML("\<", s, info, ">", x, "\</", s, ">", ...)
}

getAttrSDML <- function(x)
{
	if (!is.null(x$attributes))
	{
		return(x$attributes)
	}
	return(NULL)
}
writeDatasetSDML <- function(x,
                             file,
                             textdata,
                             sep,
                             na.string,
                             null.string,
                             posinf.string,
                             neginf.string,
                             nan.string,
                             true,
                             false
                             )
{
    ## 2nd level function: responsible for the correct 
    ## choice of StatDataML objects, currently only lists and arrays

    if (is.null(x)) return(NULL)
    
    catSDML("<dataset>\n", file = file)
    
    writeListArraySDML(x, file = file, textdata = textdata,
                       sep = sep, na.string = na.string,
                       null.string = null.string, posinf.string = posinf.string,
                       neginf.string = neginf.string, nan.string = nan.string,
                       true = true, false = false)
    
    catSDML("</dataset>\n", file = file)
}




writeDescriptionSDML <- function(title = "RDataset",
                                 source = "R",
                                 version = " ",
                                 date = NULL,
                                 comment = "",
                                 properties = NULL,
                                 file = "",
                                 textdata,
                                 sep,
                                 na.string,
                                 null.string,
                                 posinf.string,
                                 neginf.string,
                                 nan.string,
                                 true,
                                 false)
{
    ## writes the description tag to file
    markup <- function(x)
      gsub("<", "&lt;", gsub(">", "&gt;", gsub("&", "&amp;", x)))
    
    catSDML("<description>\n", file = file)
    catSDML("<title>", markup(title), "</title>\n", file = file)
    catSDML("<source>", markup(source), "</source>\n", file = file)
    cat("<date>", markup(date), "</date>\n", file = file, append = TRUE, sep = " ")
    catSDML("<version>", markup(version), "</version>\n", file = file)
    catSDML("<comment>", markup(comment), "</comment>\n", file = file)
    sdmlib <- .path.package("StatDataML")
    sdmlib <- substr(sdmlib, 1, nchar(sdmlib)-10)
    catSDML("<creator>R-", R.version$major, ".",  R.version$minor,
            ":StatDataML_",
            package.description("StatDataML", lib=sdmlib)$Version,
            "</creator>\n", file = file)
    if (!is.null(properties)) {
      catSDML("<properties>\n", file = file)

      if (!is.list(properties))
        properties <- list(properties)
      writeListArraySDML(properties, file = file, textdata = textdata,
                         sep = sep, na.string = na.string,
                         null.string = null.string, posinf.string = posinf.string,
                         neginf.string = neginf.string, nan.string = nan.string,
                         true = true, false = false)
      
      catSDML("</properties>\n", file = file)
    }
    catSDML("</description>\n", file = file)
}


writeListArraySDML <- function(x,
                               file,
                               textdata,
                               sep,
                               na.string,
                               null.string,
                               posinf.string,
                               neginf.string,
                               nan.string,
                               true,
                               false)
{
  if (is.null(x))
    catSDML("\<empty/>\n", file = file)
  else if (is.recursive(x) && !is.call(x) && !is.environment(x)) {	
    catSDML("\<list>\n", file = file)
    writeDimensionSDML(x, file = file)
    writePropertiesSDML(attributes(x), file = file, textdata = textdata,
           sep = sep, na.string = na.string, null.string = null.string,
           posinf.string = posinf.string, neginf.string = neginf.string,
           nan.string = nan.string, true = true, false = false)
                            
    catSDML("\<listdata>\n", file = file)		
    lapply(x, writeListArraySDML, file = file, textdata = textdata,
           sep = sep, na.string = na.string, null.string = null.string,
           posinf.string = posinf.string, neginf.string = neginf.string,
           nan.string = nan.string, true = true, false = false)
    catSDML("\</listdata>\n", file = file)	
    catSDML("\</list>\n", file = file)
  } else {
    catSDML("\<array>\n", file = file)

    if (is.recursive(x)) x <- deparse(x)

    ## dimension tag
    writeDimensionSDML(x, file = file)

    ## prepare properties tag:
    ## check the datatype
    type <- if (inherits(x, "POSIXt"))
      "datetime"
    else if (is.character(x))
      "character"
    else if (is.factor(x))
      "categorical"
    else if (is.logical(x))
      "logical"
    else
      "numeric"
    
    ## check the mode
    mode <- NULL
    if (type == "numeric")
      mode <- if (is.integer(x))
        "integer"
      else if (is.real(x))
        "real"
      else
        "complex"
    if (type == "categorical")
      mode <- if (is.ordered(x))
        "ordered"
      else
        "unordered"
    
    ## write type tag
    writeTypeSDML(x, type, mode, file = file)

    ## write properties tag
    ## remove factor/POSIXxx attributes first
    xtmp <- x
    if (is.factor(x)) {
      attr(xtmp, "levels") <- NULL
      newclass <- class(xtmp)[!class(xtmp) %in% c("ordered","factor")]
      class(xtmp) <- if (!length(newclass)) NULL else newclass
    }
    if (inherits(x, "POSIXt")) {
      newclass <- class(xtmp)[!class(xtmp) %in% c("POSIXt","POSIXct","POSIXlt")]
      class(xtmp) <- if(!length(newclass)) NULL else newclass
    }

    writePropertiesSDML(attributes(xtmp), file = file,
                        sep = sep, na.string = na.string, null.string = null.string,
                        posinf.string = posinf.string, neginf.string = neginf.string,
                        nan.string = nan.string, true = true, false = false)

    if (is.null(textdata))
      textdata <- type != "character" && type != "datetime"
    
    x <- switch (type,
                 logical = if (textdata) ifelse(x, true, false) else x,
                 categorical = as.numeric(x),
                 numeric = x,
                 datetime = as.character(x, format="%Y-%m-%dT%H:%M:%S"),
                 character = gsub("<", "&lt;", gsub(">", "&gt;", gsub("&", "&amp;", x)))
                 )

    if (textdata) {
      ## textdata tag
      catSDML("\<textdata sep=\"", sep, "\"",
              if (any(is.na(x[!is.nan(x)])))
                paste(" na.string=\"", na.string, "\"", sep = ""),
              if (type == "character")
                paste(" null.string=\"", null.string, "\"", sep = ""),
              if (type == "numeric") paste(
                    if (any(is.nan(x)))
                      paste(" nan.string=\"", nan.string, "\"", sep = ""),
                    if (any(x == Inf, na.rm = TRUE))
                      paste(" posinf.string=\"", posinf.string, "\"", sep = ""),
                    if (any(x == -Inf, na.rm = TRUE))
                      paste(" neginf.string=\"", neginf.string, "\"", sep = ""),
                    sep = ""),
              if (type == "logical") paste(
                    if (any(x == true, na.rm = TRUE))
                      paste(" true=\"", true, "\"", sep=""),
                    if (any(x == false, na.rm = TRUE))
                      paste(" false=\"", false, "\"", sep=""),
                    sep = ""),
              ">",
              file = file
              )
      if (length(x)) {
        catSDML("\n", file = file)
      
        ## replacements
        x <- as.character(x)

        x[is.na(x)] <- na.string
        x[x == ""] <- null.string
      
        if (type == "numeric") {
          x <- gsub("NaN", nan.string, x)
          x <- gsub("^Inf", posinf.string, x)
          x <- gsub("-Inf", neginf.string, x)
        }

        if (type == "logical") {
          x[x == "TRUE"] <- true
          x[x == "FALSE"] <- false
        }

        ## write data
        cat(x, sep=c(rep(substr(sep, 1, 1), 9), "\n"), file = file, append = TRUE)
      }
      
      catSDML("</textdata>\n", file = file)
    } else {
      ## data tag
      catSDML("<data>", file = file)

      if (length(x)) {
        catSDML("\n", file = file)
      
        if(!is.null(a <- attr(xtmp, "info")))
          attr(x, "info") <- a

        ## write data
        if (type == "numeric" && !is.null(mode) && mode == "complex")
          cetagsSDML(x, file = file)
        else
          etagsSDML(x, file = file)
        
        catSDML("\n", file = file)
      }
      catSDML("</data>\n", file = file)
    }
    catSDML("</array>\n", file=file)
  }
}

writeDimensionSDML <- function(x, file = "") 
{
  ## make dataframes behave themselves
  x <- unclass(x)
  
  catSDML("\<dimension>", file = file)
  if (length(x)) catSDML("\n", file = file)
  
  if (!is.null(dim(x))) {
    for (i in 1:length(dim(x))) {	
      catSDML("\<dim size=\"", dim(x)[i], "\"",
              if (!is.null(names(dimnames(x))[i]))
              paste(" name=\"", names(dimnames(x))[i], "\"", sep = ""),
              "\>", file = file)
      
      if (!is.null(dimnames(x)[[i]]))
        etagsSDML(dimnames(x)[[i]], file = file)
      
      catSDML("\</dim>\n", file = file)
    }
  } else if (length(x)) {
    catSDML("\<dim size=\"", length(x), "\"\>", file = file)
    
    if (!is.null(names(x)))
      etagsSDML(names(x), file = file)
    
    catSDML("\</dim>\n", file = file)
  }
  
  catSDML("\</dimension>\n", file = file)	
}

writePropertiesSDML <- function(attrib, file, textdata, ...)
{
  attrib[["dim"]] <- NULL
  attrib[["names"]] <- NULL
  attrib[["dimnames"]] <- NULL
  attrib[["length"]] <- NULL
  
  if (!is.null(attrib) && length(attrib) > 0) {
    catSDML("\<properties>\n", file = file)
    
    writeListArraySDML(attrib, file = file, textdata = FALSE, ...)
    
    catSDML("\</properties>\n", file = file)	
  }
}

writeTypeSDML <- function(x, type, mode, file)
{
  catSDML("\<type>", file = file)

  if (type %in% c("logical", "character", "datetime"))
    catSDML(" \<", type, "/\> ", file = file)
  else if (type == "numeric") {
    catSDML("\<numeric\>", file = file)
    if (mode == "complex") {
      catSDML("\n\<complex/\>\n", file = file)
    } else {
      catSDML("\<",mode,"\>\n", file = file)
      tags(min(x, na.rm = TRUE), "min", file = file)
      tags(max(x, na.rm = TRUE), "max", file = file)
      catSDML("\n\</",mode,"\>", file = file)
    }
    
    catSDML("\</numeric>", file = file)	
  } else {## categorical
    catSDML("\n\<categorical mode=\"", mode, "\"\>\n", file = file)
    for (i in 1:length(levels(x)))
      catSDML("\<label code=\"", i, "\">", levels(x)[i], "\</label\>\n", file = file)
    catSDML("</categorical\>\n", file = file)	
  }
  
  catSDML("\</type>\n", file = file)	
}


writeSDML <- function(x,
                      file = "",
                      textdata = NULL,
                      dtd = NULL,
                      sep = " &#x000A;&#x000D;",
                      na.string = "NA",
                      null.string = "NULL",
                      posinf.string = "+Inf",
                      neginf.string = "-Inf",
                      nan.string = "NaN",
                      true = "1",
                      false = "0",
                      title = deparse(substitute(x)),
                      source = "R",
                      version = " ",
                      date = NULL,
                      comment = " ",
                      properties = NULL)
{
  if (is.null(date)) date <- date()
  if (is.null(dtd))
    dtd <- system.file("dtd/StatDataML.dtd", package = "StatDataML")[1]
  
  cat("\<\?xml version=\"1.0\"\?>\n", file = file, sep = "")
  catSDML("\<!DOCTYPE StatDataML PUBLIC \"StatDataML.dtd\" \"", dtd,
      "\" >\n", file = file)
  catSDML("\<StatDataML xmlns=\"http://www.omegahat.org/StatDataML/\">\n", file = file)
  
  writeDescriptionSDML(title = title, source = source,
                       version = version, date = date,
                       comment = comment, file = file,
                       properties = properties,
                       textdata = textdata, sep = sep,
                       na.string = na.string, null.string = null.string,
                       posinf.string = posinf.string, neginf.string = neginf.string,
                       true = true, false = false, nan.string = nan.string)
  
  writeDatasetSDML(x, file = file, textdata = textdata, sep = sep,
                   na.string = na.string, null.string = null.string,
                   posinf.string = posinf.string, neginf.string = neginf.string,
                   true = true, false = false, nan.string = nan.string)
  
  catSDML("\</StatDataML>\n", file = file)
}



require(XML)
