8176447: javax.xml.validation.Validator validates incorrectly on uniqueness constraint
Reviewed-by: lancea
This commit is contained in:
parent
365d1188bf
commit
5dcfefbae0
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
*/
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
@ -37,6 +37,7 @@ import org.xml.sax.SAXException;
|
||||
* @xerces.internal
|
||||
*
|
||||
* @author Andy Clark, IBM
|
||||
* @LastModified: July 2019
|
||||
*
|
||||
*/
|
||||
public class XPathMatcher {
|
||||
@ -88,25 +89,25 @@ public class XPathMatcher {
|
||||
//
|
||||
|
||||
/** XPath location path. */
|
||||
private XPath.LocationPath[] fLocationPaths;
|
||||
private final XPath.LocationPath[] fLocationPaths;
|
||||
|
||||
/** True if XPath has been matched. */
|
||||
private int[] fMatched;
|
||||
private final int[] fMatched;
|
||||
|
||||
/** The matching string. */
|
||||
protected Object fMatchedString;
|
||||
|
||||
/** Integer stack of step indexes. */
|
||||
private IntStack[] fStepIndexes;
|
||||
private final IntStack[] fStepIndexes;
|
||||
|
||||
/** Current step. */
|
||||
private int[] fCurrentStep;
|
||||
private final int[] fCurrentStep;
|
||||
|
||||
/**
|
||||
* No match depth. The value of this field will be zero while
|
||||
* matching is successful for the given xpath expression.
|
||||
*/
|
||||
private int [] fNoMatchDepth;
|
||||
private final int [] fNoMatchDepth;
|
||||
|
||||
final QName fQName = new QName();
|
||||
|
||||
@ -207,7 +208,7 @@ public class XPathMatcher {
|
||||
*
|
||||
* @throws SAXException Thrown by handler to signal an error.
|
||||
*/
|
||||
public void startElement(QName element, XMLAttributes attributes){
|
||||
public void startElement(QName element, XMLAttributes attributes) {
|
||||
if (DEBUG_METHODS2) {
|
||||
System.out.println(toString()+"#startElement("+
|
||||
"element={"+element+"},"+
|
||||
@ -215,7 +216,7 @@ public class XPathMatcher {
|
||||
")");
|
||||
}
|
||||
|
||||
for(int i = 0; i < fLocationPaths.length; i++) {
|
||||
for (int i = 0; i < fLocationPaths.length; i++) {
|
||||
// push context
|
||||
int startStep = fCurrentStep[i];
|
||||
fStepIndexes[i].push(startStep);
|
||||
@ -284,18 +285,16 @@ public class XPathMatcher {
|
||||
if (DEBUG_MATCH) {
|
||||
System.out.println(toString()+" [CHILD] before");
|
||||
}
|
||||
if (nodeTest.type == XPath.NodeTest.QNAME) {
|
||||
if (!nodeTest.name.equals(element)) {
|
||||
if(fCurrentStep[i] > descendantStep) {
|
||||
fCurrentStep[i] = descendantStep;
|
||||
continue;
|
||||
}
|
||||
fNoMatchDepth[i]++;
|
||||
if (DEBUG_MATCH) {
|
||||
System.out.println(toString()+" [CHILD] after NO MATCH");
|
||||
}
|
||||
if (!matches(nodeTest, element)) {
|
||||
if (fCurrentStep[i] > descendantStep) {
|
||||
fCurrentStep[i] = descendantStep;
|
||||
continue;
|
||||
}
|
||||
fNoMatchDepth[i]++;
|
||||
if (DEBUG_MATCH) {
|
||||
System.out.println(toString()+" [CHILD] after NO MATCH");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
fCurrentStep[i]++;
|
||||
if (DEBUG_MATCH) {
|
||||
@ -303,10 +302,11 @@ public class XPathMatcher {
|
||||
}
|
||||
}
|
||||
if (fCurrentStep[i] == steps.length) {
|
||||
if(sawDescendant) {
|
||||
if (sawDescendant) {
|
||||
fCurrentStep[i] = descendantStep;
|
||||
fMatched[i] = MATCHED_DESCENDANT;
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
fMatched[i] = MATCHED;
|
||||
}
|
||||
continue;
|
||||
@ -324,8 +324,7 @@ public class XPathMatcher {
|
||||
|
||||
for (int aIndex = 0; aIndex < attrCount; aIndex++) {
|
||||
attributes.getName(aIndex, fQName);
|
||||
if (nodeTest.type != XPath.NodeTest.QNAME ||
|
||||
nodeTest.name.equals(fQName)) {
|
||||
if (matches(nodeTest, fQName)) {
|
||||
fCurrentStep[i]++;
|
||||
if (fCurrentStep[i] == steps.length) {
|
||||
fMatched[i] = MATCHED_ATTRIBUTE;
|
||||
@ -384,7 +383,7 @@ public class XPathMatcher {
|
||||
"element={"+element+"},"+
|
||||
")");
|
||||
}
|
||||
for(int i = 0; i<fLocationPaths.length; i++) {
|
||||
for (int i = 0; i < fLocationPaths.length; i++) {
|
||||
// go back a step
|
||||
fCurrentStep[i] = fStepIndexes[i].pop();
|
||||
|
||||
@ -395,10 +394,13 @@ public class XPathMatcher {
|
||||
|
||||
// signal match, if appropriate
|
||||
else {
|
||||
int j=0;
|
||||
for(; j<i && ((fMatched[j] & MATCHED) != MATCHED); j++);
|
||||
if ((j<i) || (fMatched[j] == 0) ||
|
||||
((fMatched[j] & MATCHED_ATTRIBUTE) == MATCHED_ATTRIBUTE)) {
|
||||
int j = 0;
|
||||
for(; j < i && ((fMatched[j] & MATCHED) != MATCHED); j++);
|
||||
if ((j < i) || (fMatched[j] == 0)) {
|
||||
continue;
|
||||
}
|
||||
if ((fMatched[j] & MATCHED_ATTRIBUTE) == MATCHED_ATTRIBUTE) {
|
||||
fMatched[i] = 0;
|
||||
continue;
|
||||
}
|
||||
// only certain kinds of matchers actually
|
||||
@ -476,6 +478,18 @@ public class XPathMatcher {
|
||||
return str.toString();
|
||||
} // normalize(String):String
|
||||
|
||||
/** Returns true if the given QName matches the node test. **/
|
||||
private static boolean matches(XPath.NodeTest nodeTest, QName value) {
|
||||
if (nodeTest.type == XPath.NodeTest.QNAME) {
|
||||
return nodeTest.name.equals(value);
|
||||
}
|
||||
if (nodeTest.type == XPath.NodeTest.NAMESPACE) {
|
||||
return nodeTest.name.uri == value.uri;
|
||||
}
|
||||
// XPath.NodeTest.WILDCARD
|
||||
return true;
|
||||
} // matches(XPath.NodeTest,QName):boolean
|
||||
|
||||
//
|
||||
// MAIN
|
||||
//
|
||||
|
@ -36,11 +36,12 @@ import org.testng.annotations.DataProvider;
|
||||
|
||||
import org.testng.annotations.Listeners;
|
||||
import org.testng.annotations.Test;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.SAXParseException;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8220818
|
||||
* @bug 8220818 8176447
|
||||
* @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest
|
||||
* @run testng/othervm validation.ValidationTest
|
||||
* @summary Runs validations with schemas and sources
|
||||
@ -71,6 +72,17 @@ public class ValidationTest {
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
DataProvider: uniqueness
|
||||
*/
|
||||
@DataProvider(name = "uniqueness")
|
||||
Object[][] getUniqueData() {
|
||||
return new Object[][]{
|
||||
{"JDK8176447a.xsd", "JDK8176447a.xml"},
|
||||
{"JDK8176447b.xsd", "JDK8176447b.xml"},
|
||||
};
|
||||
}
|
||||
|
||||
@Test(dataProvider = "invalid", expectedExceptions = SAXParseException.class)
|
||||
public void testValidateRefType(String xsd, String xml) throws Exception {
|
||||
validate(xsd, xml);
|
||||
@ -81,6 +93,19 @@ public class ValidationTest {
|
||||
validate(xsd, xml);
|
||||
}
|
||||
|
||||
/**
|
||||
* @bug 8176447
|
||||
* Verifies that the uniqueness constraint is checked.
|
||||
* @param xsd the XSD
|
||||
* @param xml the XML
|
||||
* @throws Exception expected when the uniqueness constraint is validated
|
||||
* correctly.
|
||||
*/
|
||||
@Test(dataProvider = "uniqueness", expectedExceptions = SAXException.class)
|
||||
public void testUnique(String xsd, String xml) throws Exception {
|
||||
validate(xsd, xml);
|
||||
}
|
||||
|
||||
private void validate(String xsd, String xml) throws Exception {
|
||||
final SchemaFactory schemaFactory = SchemaFactory.newInstance(
|
||||
XMLConstants.W3C_XML_SCHEMA_NS_URI);
|
||||
@ -90,4 +115,5 @@ public class ValidationTest {
|
||||
validator.validate(new StreamSource(
|
||||
new File(getClass().getResource(FILE_PATH + xml).getFile())));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
<test xmlns="http://openjdk_java_net/test.xml"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="JDK8176447a.xsd">
|
||||
<innerObject>
|
||||
<innerInnerObject test-unique-attribute="1" />
|
||||
<innerInnerObject test-unique-attribute="1" />
|
||||
</innerObject>
|
||||
</test>
|
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:h="http://www.w3.org/1999/xhtml"
|
||||
xmlns:sn="http://openjdk_java_net/test.xml"
|
||||
targetNamespace="http://openjdk_java_net/test.xml" elementFormDefault="qualified">
|
||||
<xsd:element name="test" type="sn:object">
|
||||
<xsd:unique name="testunique">
|
||||
<xsd:selector xpath="sn:innerObject"/>
|
||||
<xsd:field xpath="sn:innerInnerObject/@test-unique-attribute"/>
|
||||
</xsd:unique>
|
||||
</xsd:element>
|
||||
<xsd:complexType name="object">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="innerObject" maxOccurs="unbounded" type="sn:testType" />
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="testType">
|
||||
<xsd:sequence>
|
||||
<xsd:element name="innerInnerObject" maxOccurs="unbounded" type="sn:testObjectType"/>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
<xsd:complexType name="testObjectType">
|
||||
<xsd:attribute use="optional" name="test-unique-attribute" type="xsd:int" />
|
||||
</xsd:complexType>
|
||||
</xsd:schema>
|
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="JDK8176447b.xsd">
|
||||
<e>
|
||||
<e1 a1="a" >
|
||||
<e2 a2="a"/>
|
||||
<e2 a2="a"/>
|
||||
</e1>
|
||||
<e1 a1="a">
|
||||
<e2 a2="b"/>
|
||||
<e2 a2="a"/>
|
||||
</e1>
|
||||
</e>
|
||||
</root>
|
@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
|
||||
<xs:element name="root">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element name="e" maxOccurs="unbounded">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element maxOccurs="unbounded" name="e1">
|
||||
<xs:complexType>
|
||||
<xs:sequence>
|
||||
<xs:element maxOccurs="unbounded" name="e2">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="a2" use="required" type="xs:NCName"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
<xs:attribute name="a1" use="required" type="xs:NCName"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
|
||||
<xs:key name="checkAttrib">
|
||||
<xs:selector xpath=".//e1"/>
|
||||
<xs:field xpath="@a1"/>
|
||||
<xs:field xpath="e2/@a2"/>
|
||||
</xs:key>
|
||||
|
||||
</xs:element>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:schema>
|
Loading…
x
Reference in New Issue
Block a user