1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 package com.jcabi.w3c;
31
32 import com.jcabi.aspects.Immutable;
33 import com.jcabi.http.Request;
34 import com.jcabi.http.Response;
35 import com.jcabi.http.request.JdkRequest;
36 import com.jcabi.http.response.XmlResponse;
37 import com.jcabi.log.Logger;
38 import com.jcabi.xml.XML;
39 import java.io.IOException;
40 import java.net.HttpURLConnection;
41 import java.net.URI;
42 import java.nio.charset.StandardCharsets;
43 import java.util.List;
44 import javax.ws.rs.core.HttpHeaders;
45 import javax.ws.rs.core.MediaType;
46 import lombok.EqualsAndHashCode;
47 import lombok.ToString;
48
49
50
51
52
53
54
55 @Immutable
56 @ToString
57 @EqualsAndHashCode(callSuper = false, of = "uri")
58 final class DefaultHtmlValidator
59 extends AbstractBaseValidator implements Validator {
60
61
62
63
64 private final transient String uri;
65
66
67
68
69
70 DefaultHtmlValidator(final URI entry) {
71 super();
72 this.uri = entry.toString();
73 }
74
75 @Override
76 public ValidationResponse validate(final String html)
77 throws IOException {
78 final Request req = this.request(html);
79 final Response response = req.fetch();
80 if (response.status() != HttpURLConnection.HTTP_OK) {
81 throw new IOException(
82 response.reason()
83 );
84 }
85 return this.build(
86 response.as(XmlResponse.class)
87 .registerNs("nu", "http://n.validator.nu/messages/")
88 .assertXPath("//nu:messages")
89 .assertXPath("//nu:source")
90 .xml()
91 );
92 }
93
94
95
96
97
98
99 private Request request(final String entity) {
100 return new JdkRequest(this.uri)
101 .method(Request.POST)
102 .body().set(entity).back()
103 .header(HttpHeaders.USER_AGENT, AbstractBaseValidator.USER_AGENT)
104 .header(HttpHeaders.ACCEPT, MediaType.TEXT_HTML)
105 .header(
106 HttpHeaders.CONTENT_TYPE,
107 Logger.format(
108 "%s; charset=%s",
109 MediaType.TEXT_HTML,
110 StandardCharsets.UTF_8
111 )
112 );
113 }
114
115
116
117
118
119
120 private ValidationResponse build(final XML xml) {
121 final List<XML> errors = xml.nodes("//nu:error");
122 final List<XML> warnings = xml.nodes("//nu:info");
123 final DefaultValidationResponse resp = new DefaultValidationResponse(
124 errors.isEmpty() && warnings.isEmpty(),
125 URI.create(this.uri),
126 AbstractBaseValidator.textOf(xml.xpath("//nu:source/@type")),
127 AbstractBaseValidator.charset(
128 AbstractBaseValidator.textOf(xml.xpath("//nu:source/@encoding"))
129 )
130 );
131 for (final XML node : errors) {
132 resp.addError(DefaultHtmlValidator.defect(node));
133 }
134 for (final XML node : warnings) {
135 resp.addWarning(DefaultHtmlValidator.defect(node));
136 }
137 return resp;
138 }
139
140
141
142
143
144
145 private static Defect defect(final XML node) {
146 return new Defect(
147 AbstractBaseValidator.intOf(node.xpath("nu:error/@last-line")),
148 AbstractBaseValidator.intOf(node.xpath("nu:error/@last-column")),
149 AbstractBaseValidator.textOf(node.xpath("nu:extract/text()")),
150 AbstractBaseValidator.textOf(node.xpath("nu:elaboration/text()")),
151 "",
152 AbstractBaseValidator.textOf(node.xpath("nu:message/text()"))
153 );
154 }
155 }