Skip to content
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -315,3 +315,18 @@ save_file(xdoc, filename) # save xdoc to an XML file
string(xdoc) # formatted XML doc to a string
show(io, xdoc) # output formatted XML document
```

##### Functions to validate a document

```julia
xsd = XMLSchema(url) # parse an XSD schema file or URL

isvalid = validate(xmlfile, schema) # validate an XML file against a previously loaded XSD schema
isvalid = validate(doc, schema) # validate a LightXML XML Document against a previously loaded XSD schema
isvalid = validate(url, schema) # validate a URI or file against an XSD Schema document
isvalid = validate(element, schema) # validate a LightXML XML Node (a subtree) against an XSD Schema document

isvalid = validate(xmlfile, schemafile) # validate an XML file or URL against a XSD schem file or URL
```


6 changes: 5 additions & 1 deletion src/LightXML.jl
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ export

# document
XMLDocument, version, encoding, compression, standalone, root,
parse_file, parse_string, save_file, set_root, create_root
parse_file, parse_string, save_file, set_root, create_root,

# schema
XMLSchema, validate

const Xchar = UInt8
const Xstr = Ptr{Xchar}
Expand All @@ -43,5 +46,6 @@ include("utils.jl")
include("nodes.jl")
include("document.jl")
include("cdata.jl")
include("schema.jl")

end
4 changes: 4 additions & 0 deletions src/errors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ end
struct XMLTreeError{T<:AbstractString} <: XMLError
msg::T
end

struct XMLValidationError{T<:AbstractString} <: XMLError
msg::T
end
84 changes: 84 additions & 0 deletions src/schema.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
"""
An XML Schema Document, produced by an XML file or XMLDocument that is XML for the schema.
"""
mutable struct XMLSchema
ptr::Xptr
function XMLSchema(ctxt::Xptr)
schema = ccall((:xmlSchemaParse, libxml2), Xptr, (Xptr,), ctxt)
schema != C_NULL || throw(XMLValidationError("Bad XML Schema in Document"))
ccall((:xmlSchemaFreeParserCtxt, libxml2), Cvoid, (Xptr,), ctxt)
obj = new(schema)
finalizer((x) -> Libc.free(x.ptr), obj)
end
end

"""
Create an XMLSchema from a file or url
"""
function XMLSchema(url::String)
ctxt = ccall((:xmlSchemaNewParserCtxt, libxml2), Xptr, (Cstring,), url)
ctxt != C_NULL || throw(XMLValidationError("Bad XML Schema at " * url))
return XMLSchema(ctxt)
end

"""
Create an XMLSchema from an XMLDocument
"""
function XMLSchema(doc::XMLDocument)
ctxt = ccall((:xmlSchemaNewDocParserCtxt, libxml2), Xptr, (Xptr,), doc.ptr)
ctxt != C_NULL || throw(XMLValidationError("Bad XML Schema in Document"))
return XMLSchema(ctxt)
end

"""
Validate an XMLDocument with an XMLSchema
Returns true if valid
"""
function validate(xml::XMLDocument, schema::XMLSchema)
ctxt = ccall((:xmlSchemaNewValidCtxt, libxml2), Xptr, (Xptr,), schema.ptr)
err = ccall((:xmlSchemaValidateDoc, libxml2),
Cint, (Xptr, Xptr), ctxt, xml.ptr)
Libc.free(ctxt)
return err == 0 ? true : false
end

"""
Validate an XML file or url with an XMLSchema
Returns true if valid
"""
function validate(url::String, schema::XMLSchema)
ctxt = ccall((:xmlSchemaNewValidCtxt, libxml2), Xptr, (Xptr,), schema.ptr)
err = ccall((:xmlSchemaValidateFile, libxml2),
Cint, (Xptr, Cstring), ctxt, url)
Libc.free(ctxt)
return err == 0 ? true : false
end

"""
Validate an XMLElement of an XMLDocument with an XMLSchema
Returns true if valid
"""
function validate(elem::XMLElement, schema::XMLSchema)
ctxt = ccall((:xmlSchemaNewValidCtxt, libxml2), Xptr, (Xptr,), schema.ptr)
err = ccall((:xmlSchemaValidateOneElement, libxml2),
Cint, (Xptr, Xptr), ctxt, elem.node.ptr)
Libc.free(ctxt)
return err == 0 ? true : false
end

"""
Validate an XML file or url with an XSD file or url
Returns true if valid
"""
function validate(url::String, schemafile::String)
ctxt = ccall((:xmlSchemaNewParserCtxt, libxml2), Xptr, (Cstring,), schemafile)
ctxt != C_NULL || throw(XMLValidationError("Bad XML Schema at " * schemafile))
schema = ccall((:xmlSchemaParse, libxml2), Xptr, (Xptr,), ctxt)
schema != C_NULL || throw(XMLValidationError("Bad XML Schema at " * url))
ccall((:xmlSchemaFreeParserCtxt, libxml2), Cvoid, (Xptr,), ctxt)
ctxt = ccall((:xmlSchemaNewValidCtxt, libxml2), Xptr, (Xptr,), schema)
err = ccall((:xmlSchemaValidateFile, libxml2),
Cint, (Ptr{LightXML.xmlBuffer}, Cstring), ctxt, url)
Libc.free(ctxt)
return err == 0 ? true : false
end
2 changes: 1 addition & 1 deletion test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using LightXML
using Test

tests = ["parse", "create", "cdata", "pi"]
tests = ["parse", "create", "cdata", "pi", "validate"]

for t in tests
fpath = "$t.jl"
Expand Down
24 changes: 24 additions & 0 deletions test/valid.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>

<shiporder orderid="889923"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="shiporder.xsd">
<orderperson>John Smith</orderperson>
<shipto>
<name>Ola Nordmann</name>
<address>Langgt 23</address>
<city>4000 Stavanger</city>
<country>Norway</country>
</shipto>
<item>
<title>Empire Burlesque</title>
<note>Special Edition</note>
<quantity>1</quantity>
<price>10.90</price>
</item>
<item>
<title>Hide your heart</title>
<quantity>1</quantity>
<price>9.90</price>
</item>
</shiporder>
33 changes: 33 additions & 0 deletions test/valid.xsd
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

<xs:element name="shiporder">
<xs:complexType>
<xs:sequence>
<xs:element name="orderperson" type="xs:string"/>
<xs:element name="shipto">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"/>
<xs:element name="address" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="country" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="item" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="title" type="xs:string"/>
<xs:element name="note" type="xs:string" minOccurs="0"/>
<xs:element name="quantity" type="xs:positiveInteger"/>
<xs:element name="price" type="xs:decimal"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="orderid" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>

</xs:schema>
13 changes: 13 additions & 0 deletions test/validate.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@test validate("valid.xml", "valid.xsd") == true

@test validate("valid.xml", "valid.xsd") == true

doc = parse_file("valid.xml")
schema = XMLSchema("valid.xsd")

@test validate("valid.xml", schema) == true

@test validate(doc, schema) == true

@test validate(root(doc), schema) == true