XSD validation: cache invalidation stopped working
Thursday, 26 December 2024 · 5 messages · last reply 30 Dec 2024
Y
ykhabins26 Dec 2024 17:06 #
Hello,
My environment has BaseX 11.6 installed.
The XQuery is called in c# via REST HTTP call:
string REQUESTURL =
$"http://{HOST}:{PORT}/rest?run={XQUERY}&$xml={xmlFile}&$xsd={xsdFile}";
XQuery is using XSD validation with caching, along the following: let $result :=
validate:xsd-report($xml, $xsd, map {
'http://apache.org/xml/features/validation/cta-full-xpath-checking': true(), 'cache': true() })
It seems that the cache invalidation call stopped working ?! It is not picking up the latest XSD.
I launch it from the BaseX GUI as follows:
validate:xsd-init()
Just restart of the HTTP listener picks up the latest/modified XSD.
Please advise.
Regards,
Yitzhak KhabinskyCG
Christian Grün29 Dec 2024 21:26 #
Hi Yitzhak,
A self-contained example would be helpful.
Thanks in advance,
Christian
Quoted text · PM · 30 lines
On Thu, Dec 26, 2024 at 4:07 PM <ykhabins at bellsouth.net> wrote: > Hello, > > My environment has BaseX 11.6 installed. > > The XQuery is called in c# via REST HTTP call: > string REQUESTURL = > $"http://{HOST}:{PORT}/rest?run={XQUERY}&$xml={xmlFile}&$xsd={xsdFile}"; > > XQuery is using XSD validation with caching, along the following: > let $result := validate:xsd-report($xml, $xsd, map { > 'http://apache.org/xml/features/validation/cta-full-xpath-checking': > true(), > 'cache': true() }) > > It seems that the cache invalidation call stopped working ?! > It is not picking up the latest XSD. > > I launch it from the BaseX GUI as follows: > validate:xsd-init() > > Just restart of the HTTP listener picks up the latest/modified XSD. > > Please advise. > > Regards, > Yitzhak Khabinsky > > >
Y
ykhabins30 Dec 2024 04:53 #
Here is a full repro.
Initial setup, four files:
1) XML: e:\Temp\XSD_CACHE\input.xml
2) XSD: e:\Temp\XSD_CACHE\state.xsd
3) XQuery: c:\Program Files (x86)\BaseX\webapp\XSD11_Validation_RECEIPT_2.xq
4) c# file making BaseX REST HTTP call
XML file: e:\Temp\XSD_CACHE\input.xml
======================================
<?xml version="1.0"?>
<root>
<state>FL</state>
<state>TX</state>
</root>
XSD file: e:\Temp\XSD_CACHE\state.xsd
=========================================
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified" version="1.0.0">
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded"
ref="state"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="state" type="state_type"/>
<xs:simpleType name="state_type">
<xs:restriction base="xs:string">
<xs:length value="2"/>
<xs:enumeration value="FL"/>
<!--<xs:enumeration value="TX"/>-->
</xs:restriction>
</xs:simpleType>
</xs:schema>XQuery file: XSD11_Validation_RECEIPT_2.xq
==========================================
declare variable $xml as xs:string external;
declare variable $xsd as xs:string external;
try
{
let $timezone := timezone-from-dateTime(current-dateTime())
let $before_datetime :=
adjust-dateTime-to-timezone(
convert:integer-to-dateTime(prof:current-ms()), xs:dayTimeDuration($timezone)) (: current-dateTime() :)
let $result := validate:xsd-report($xml, $xsd, map {
'http://apache.org/xml/features/validation/cta-full-xpath-checking': true(), 'cache': true() })
let $after_datetime :=
adjust-dateTime-to-timezone(convert:integer-to-dateTime(prof:current-ms()), xs:dayTimeDuration($timezone)) (: current-dateTime() :)return <root><metadata>
<result>{data($result/status)}</result>
<errors>{count($result/message[@level="Error"])}</errors>
<warnings>{count($result/message[@level="Warning"])}</warnings>
<startTime>{$before_datetime}</startTime>
<endTime>{$after_datetime}</endTime>
<xmlFile>{$xml}</xmlFile>
<xsdFile>{$xsd}</xsdFile>
<xsdProcessor>BaseX {data(db:system()//version)}, Java
{proc:property('java.vendor')} v.{proc:property('java.runtime.version')},
{validate:xsd-processor()} 2.12.2</xsdProcessor>
<xsdVersion>{data(doc($xsd)/*:schema/@version)}</xsdVersion>
</metadata>
<messages>{
$result/message transform with
{ delete node @url }
}</messages>
</root>
}
catch *
{
<error>
<errorCode>{$err:code}</errorCode>
<errorDescription>{$err:description}</errorDescription>
</error>
}c# REST HTTP call:
==================
void Main()
{
const string HOST = "HostName";
const int PORT = 8080;
const string USERNAME = "username";
const string PASSWORD = "password"; System.Net.ServicePointManager.SecurityProtocol =
SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 |
SecurityProtocolType.Tls;
const string XQUERY = "XSD11_Validation_RECEIPT_2.xq";
string xmlFile = @"e:\Temp\XSD_CACHE\input.xml";
string xsdFile = @"e:\Temp\XSD_CACHE\state.xsd";
string REQUESTURL =
$"http://{HOST}:{PORT}/rest?run={XQUERY}&$xml={xmlFile}&$xsd={xsdFile}"; try
{
using (HttpClientHandler handler = new HttpClientHandler() {UseDefaultCredentials = true})
// for mdpd proxy
//{UseDefaultCredentials = true, UseProxy = true,
DefaultProxyCredentials = CredentialCache.DefaultNetworkCredentials}) using (HttpClient client = new HttpClient(handler))
{
// Encode username and password pair with a base64
implementation.
String encoded =
Convert.ToBase64String(Encoding.UTF8.GetBytes(USERNAME + ":" +
PASSWORD));
client.DefaultRequestHeaders.Add("Authorization",
"Basic " + encoded);
client.DefaultRequestHeaders.Accept.Add(new
MediaTypeWithQualityHeaderValue("application/xml"));
var response = client.GetAsync(REQUESTURL).Result;
System.Net.Http.HttpContent content =
response.Content;
var contentString =
content.ReadAsStringAsync().Result; // get the actual content string
if (response.StatusCode == HttpStatusCode.OK) //
200 //IsSuccessStatusCode == True
{
XDocument xdoc2 =
XDocument.Parse(contentString);
Console.WriteLine(xdoc2);
string fileRECEIPT =
$@"{Path.Combine(Path.GetDirectoryName(xmlFile),Path.GetFileNameWithoutExtension(xmlFile))}_RECEIPT_{DateTime.Now.ToString("
yyyy-MM-ddTHH-mm-ss")}.xml";
xdoc2.Save(fileRECEIPT, SaveOptions.None);
}
else
{
string fileErrorResponse =
$@"{Path.Combine(Path.GetDirectoryName(xmlFile),
Path.GetFileNameWithoutExtension(xmlFile))}_ErrorResponse_{DateTime.Now.ToSt
ring("yyyy-MM-ddTHH-mm-ss")}.xml";
File.WriteAllText(fileErrorResponse,
contentString);
}
}
}
catch (Exception ex)
{
ex.Message.Dump();
}
}In BaseX GUI:
SET
BINDINGS xml=e:\Temp\XSD_CACHE\input.xml,xsd=e:\Temp\XSD_CACHE\state.xsd
Start BaseX HTTP listener via launching c:\Program Files
(x86)\BaseX\bin\basexhttp.bat
First execution emits the following correct result in both BaseX GUI as well as c# REST HTTP:============================================================================
=================
<root>
<metadata>
<result>invalid</result>
<errors>2</errors>
<warnings>0</warnings>
<startTime>2024-12-29T21:00:55.659-05:00</startTime>
<endTime>2024-12-29T21:00:55.729-05:00</endTime>
<xmlFile>e:\Temp\XSD_CACHE\input.xml</xmlFile>
<xsdFile>e:\Temp\XSD_CACHE\state.xsd</xsdFile>
<xsdProcessor>BaseX 11.6, Java Eclipse Adoptium v.22.0.2+9, Xerces
2.12.2</xsdProcessor>
<xsdVersion>1.0.0</xsdVersion>
</metadata>
<messages>
<message level="Error" line="4" column="19">cvc-enumeration-valid: Value
'TX' is not facet-valid with respect to enumeration '[FL]'. It must be a
value from the enumeration.</message>
<message level="Error" line="4" column="19">cvc-type.3.1.3: The value
'TX' of element 'state' is not valid.</message>
</messages>
</root>
Modified XSD file: xsd=e:\Temp\XSD_CACHE\state.xsd
1) attribute version="1.0.1"
2) uncommented <xs:enumeration value="TX"/> to make XML file valid
==========================================================
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified" version="1.0.1">
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded"
ref="state"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="state" type="state_type"/>
<xs:simpleType name="state_type">
<xs:restriction base="xs:string">
<xs:length value="2"/>
<xs:enumeration value="FL"/>
<xs:enumeration value="TX"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>Execute in BaseX GUI:
validate:xsd-init()
Re-run c# REST HTTP CALL emits incorrect result.It shows correct xsdVersion: 1.0.1, but result is invalid with the same
error
============================================================================
=
<root>
<metadata>
<result>invalid</result>
<errors>2</errors>
<warnings>0</warnings>
<startTime>2024-12-29T21:20:07.457-05:00</startTime>
<endTime>2024-12-29T21:20:07.459-05:00</endTime>
<xmlFile>e:\Temp\XSD_CACHE\input.xml</xmlFile>
<xsdFile>e:\Temp\XSD_CACHE\state.xsd</xsdFile>
<xsdProcessor>BaseX 11.6, Java Eclipse Adoptium v.22.0.2+9, Xerces
2.12.2</xsdProcessor>
<xsdVersion>1.0.1</xsdVersion>
</metadata>
<messages>
<message level="Error" line="4" column="19">cvc-enumeration-valid: Value
'TX' is not facet-valid with respect to enumeration '[FL]'. It must be a
value from the enumeration.</message>
<message level="Error" line="4" column="19">cvc-type.3.1.3: The value
'TX' of element 'state' is not valid.</message>
</messages>
</root>Though executing XSD11_Validation_RECEIPT_2.xq directly in the BaseX GUI emits the correct result:
<root>
<metadata>
<result>valid</result>
<errors>0</errors>
<warnings>0</warnings>
<startTime>2024-12-29T21:23:51.738-05:00</startTime>
<endTime>2024-12-29T21:23:51.739-05:00</endTime>
<xmlFile>e:\Temp\XSD_CACHE\input.xml</xmlFile>
<xsdFile>e:\Temp\XSD_CACHE\state.xsd</xsdFile>
<xsdProcessor>BaseX 11.6, Java Eclipse Adoptium v.22.0.2+9, Xerces
2.12.2</xsdProcessor>
<xsdVersion>1.0.1</xsdVersion>
</metadata>
<messages/>
</root>Just restart of the BaseX HTTP listener resolves the issue with the BaseX REST HTTP call.
Regards,
Yitzhak Khabinsky
CG
Christian Grün30 Dec 2024 09:46 #
Quoted text · ykhabins · 3 lines
> Execute in BaseX GUI: > validate:xsd-init() > Re-run c# REST HTTP CALL emits incorrect result.
Note that the GUI runs in an independent JVM; it does not influence HTTP calls.
If I got you wrong, please strip everything that does not seem to contribute to the erroneous behavior; see [1] for more information.
Best,
Christian
[1] https://sscce.org/
Y
ykhabins30 Dec 2024 16:55 #
Hello,
Quoted text · Christian Grün · 1 line
>> Note that the GUI runs in an independent JVM; it does not influence HTTP
calls.
The explanation was very helpful.
I ended up with a CURL command to invalidate XSD that is cached behind HTTP listener calls (different JVM).
curl -i -u <username>:<password> -X POST -H "Content-Type: application/xml" -d "<query
xmlns='http://basex.org/rest'><text>
validate:xsd-init()</text></query>" "http://<host>:8080/rest"
It emits the following:
HTTP/1.1 200 OK
Date: Mon, 30 Dec 2024 14:44:03 GMT
Content-Type: application/xml; charset=UTF-8
Content-Length: 0
Server: Jetty(11.0.24)
And everything is working as expected.
Thanks a lot.
Regards,
Yitzhak KhabinskyWritten for BaseX 11.6. BaseX may have changed since: please check the current documentation.
⚡Generated with XQuery