Improve comment parsing in DTD/XSD detection algorithm
Prior to this commit, XmlValidationModeDetector did not properly parse all categories of comments (described below). When such categories of comments were encountered XmlValidationModeDetector may have incorrectly detected that an XML file used a DTD when it used an XSD, or vice versa. This commit revises the parsing algorithm in XmlValidationModeDetector so that multi-line comments and multiple comments on a single line are properly recognized. Specifically, with this commit the following categories of comments are now handled properly. - Multiple comments on a single line - Multi-line comment: beginning on one line and then ending on another line with an additional comment following on that same line. - Multi-line comment: beginning at the end of XML content on one line and then spanning multiple lines. Closes gh-27915
This commit is contained in:
@@ -97,7 +97,7 @@ public class XmlValidationModeDetector {
|
||||
String content;
|
||||
while ((content = reader.readLine()) != null) {
|
||||
content = consumeCommentTokens(content);
|
||||
if (this.inComment || !StringUtils.hasText(content)) {
|
||||
if (!StringUtils.hasText(content)) {
|
||||
continue;
|
||||
}
|
||||
if (hasDoctype(content)) {
|
||||
@@ -143,11 +143,10 @@ public class XmlValidationModeDetector {
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume all leading and trailing comments in the given String and return
|
||||
* the remaining content, which may be empty since the supplied content might
|
||||
* be all comment data.
|
||||
* Consume all comments in the given String and return the remaining content,
|
||||
* which may be empty since the supplied content might be all comment data.
|
||||
* <p>This method takes the current "in comment" parsing state into account.
|
||||
*/
|
||||
@Nullable
|
||||
private String consumeCommentTokens(String line) {
|
||||
int indexOfStartComment = line.indexOf(START_COMMENT);
|
||||
if (indexOfStartComment == -1 && !line.contains(END_COMMENT)) {
|
||||
@@ -156,17 +155,15 @@ public class XmlValidationModeDetector {
|
||||
|
||||
String result = "";
|
||||
String currLine = line;
|
||||
if (indexOfStartComment >= 0) {
|
||||
if (!this.inComment && (indexOfStartComment >= 0)) {
|
||||
result = line.substring(0, indexOfStartComment);
|
||||
currLine = line.substring(indexOfStartComment);
|
||||
}
|
||||
|
||||
while ((currLine = consume(currLine)) != null) {
|
||||
if (!this.inComment && !currLine.trim().startsWith(START_COMMENT)) {
|
||||
return result + currLine;
|
||||
}
|
||||
if ((currLine = consume(currLine)) != null) {
|
||||
result += consumeCommentTokens(currLine);
|
||||
}
|
||||
return null;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,6 +24,7 @@ import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.util.xml.XmlValidationModeDetector.VALIDATION_DTD;
|
||||
import static org.springframework.util.xml.XmlValidationModeDetector.VALIDATION_XSD;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link XmlValidationModeDetector}.
|
||||
@@ -37,12 +38,29 @@ class XmlValidationModeDetectorTests {
|
||||
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = { "dtdWithTrailingComment.xml", "dtdWithLeadingComment.xml", "dtdWithCommentOnNextLine.xml",
|
||||
"dtdWithMultipleComments.xml" })
|
||||
@ValueSource(strings = {
|
||||
"dtdWithNoComments.xml",
|
||||
"dtdWithLeadingComment.xml",
|
||||
"dtdWithTrailingComment.xml",
|
||||
"dtdWithTrailingCommentAcrossMultipleLines.xml",
|
||||
"dtdWithCommentOnNextLine.xml",
|
||||
"dtdWithMultipleComments.xml"
|
||||
})
|
||||
void dtdDetection(String fileName) throws Exception {
|
||||
assertValidationMode(fileName, VALIDATION_DTD);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"xsdWithNoComments.xml",
|
||||
"xsdWithMultipleComments.xml",
|
||||
"xsdWithDoctypeInComment.xml",
|
||||
"xsdWithDoctypeInOpenCommentWithAdditionalCommentOnSameLine.xml"
|
||||
})
|
||||
void xsdDetection(String fileName) throws Exception {
|
||||
assertValidationMode(fileName, VALIDATION_XSD);
|
||||
}
|
||||
|
||||
|
||||
private void assertValidationMode(String fileName, int expectedValidationMode) throws IOException {
|
||||
try (InputStream inputStream = getClass().getResourceAsStream(fileName)) {
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "https://www.springframework.org/dtd/spring-beans-2.0.dtd">
|
||||
|
||||
<beans>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "https://www.springframework.org/dtd/spring-beans-2.0.dtd"><!-- comment --><beans><!--
|
||||
trailing comment across multiple lines -->
|
||||
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "https://www.springframework.org/dtd/spring-beans-2.0.dtd"> -->
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://www.springframework.org/schema/beans
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "https://www.springframework.org/dtd/spring-beans-2.0.dtd"> --> <!-- additional comment on same line -->
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://www.springframework.org/schema/beans
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- comment #1 --> <!-- comment #2 --> <beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://www.springframework.org/schema/beans
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd"><!--
|
||||
trailing
|
||||
comment
|
||||
-->
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="https://www.springframework.org/schema/beans
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
</beans>
|
||||
Reference in New Issue
Block a user