1
/* Copyright 2005 Elliotte Rusty Harold
3
This library is free software; you can redistribute it and/or modify
4
it under the terms of version 2.1 of the GNU Lesser General Public
5
License as published by the Free Software Foundation.
7
This library is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU Lesser General Public License for more details.
12
You should have received a copy of the GNU Lesser General Public
13
License along with this library; if not, write to the
14
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
15
Boston, MA 02111-1307 USA
17
You can contact Elliotte Rusty Harold by sending e-mail to
18
elharo@metalab.unc.edu. Please include the word "XOM" in the
19
subject line. The XOM home page is located at http://www.xom.nu/
24
import java.io.IOException;
27
import nu.xom.Attribute;
28
import nu.xom.Builder;
29
import nu.xom.Document;
30
import nu.xom.Element;
31
import nu.xom.Elements;
32
import nu.xom.IllegalDataException;
35
import nu.xom.ParsingException;
39
* Tests for <code>xml:id</code> attributes.
42
* @author Elliotte Rusty Harold
46
public class IDTest extends XOMTestCase {
49
public IDTest(String name) {
54
public void testBuilderAllowsNonNCNameXmlIdAttributes()
55
throws ParsingException, IOException {
57
Builder builder = new Builder();
58
String data = "<root xml:id='p 2'/>";
59
Document doc = builder.build(data, null);
60
Element root = doc.getRootElement();
61
Attribute id = root.getAttribute(0);
62
assertEquals("p 2", id.getValue());
67
public void testIDMustBeNCName() {
69
Attribute id = new Attribute("xml:id",
70
"http://www.w3.org/XML/1998/namespace", "name");
71
assertEquals("name", id.getValue());
74
id.setValue("not a name");
75
fail("allowed non-NCName as value of xml:id attribute");
77
catch (IllegalDataException success) {
78
assertNotNull(success.getMessage());
79
assertEquals("not a name", success.getData());
85
public void testNameSetIDMustBeNCName() {
87
Attribute id = new Attribute("id", "not a name");
90
id.setNamespace("xml",
91
"http://www.w3.org/XML/1998/namespace");
92
fail("allowed non-NCName as value of xml:id attribute");
94
catch (IllegalDataException success) {
95
assertNotNull(success.getMessage());
96
assertEquals("not a name", success.getData());
102
public void testBuilderNormalizesXmlIdAttributes()
103
throws ParsingException, IOException {
105
Builder builder = new Builder();
106
String data = "<root xml:id=' p2 '/>";
107
Document doc = builder.build(data, null);
108
Element root = doc.getRootElement();
109
String value = root.getAttributeValue("id",
110
"http://www.w3.org/XML/1998/namespace");
111
assertEquals("p2", value);
116
public void testBuilderDoesNotOverNormalizeXmlIdAttributesWithCarriageReturns()
117
throws ParsingException, IOException {
119
Builder builder = new Builder();
120
String data = "<root xml:id='
 p2 '/>";
121
Document doc = builder.build(data, null);
122
Element root = doc.getRootElement();
123
Attribute id = root.getAttribute(0);
124
assertEquals("\r\u0020p2", id.getValue());
129
public void testBuilderDoesNotOverNormalizeXmlIdAttributesWithLineFeeds()
130
throws ParsingException, IOException {
132
Builder builder = new Builder();
133
String data = "<root xml:id='
 p2 '/>";
134
Document doc = builder.build(data, null);
135
Element root = doc.getRootElement();
136
Attribute id = root.getAttribute(0);
137
assertEquals("\n\u0020p2", id.getValue());
142
public void testBuiltXmlIdAttributeHasTypeId()
143
throws ParsingException, IOException {
145
Builder builder = new Builder();
146
String data = "<root xml:id=' p2 '/>";
147
Document doc = builder.build(data, null);
148
Element root = doc.getRootElement();
149
Attribute id = root.getAttribute("id",
150
"http://www.w3.org/XML/1998/namespace");
151
assertEquals(Attribute.Type.ID, id.getType());
156
public void testConstructedXmlIdAttributeHasTypeId()
157
throws ParsingException, IOException {
159
Attribute id = new Attribute("xml:id",
160
"http://www.w3.org/XML/1998/namespace", "p2");
161
assertEquals(Attribute.Type.ID, id.getType());
166
public void testNamespaceSetXmlIdAttributeHasTypeId() {
168
Attribute id = new Attribute("id", "p2");
169
id.setNamespace("xml", "http://www.w3.org/XML/1998/namespace");
170
assertEquals(Attribute.Type.ID, id.getType());
175
public void testNameSetXmlIdAttributeHasTypeId() {
177
Attribute id = new Attribute("xml:space",
178
"http://www.w3.org/XML/1998/namespace", "preserve");
179
id.setLocalName("id");
180
assertEquals(Attribute.Type.ID, id.getType());
185
public void testNameSetXmlIdAttributeMustBeNCName() {
187
Attribute id = new Attribute("xml:space",
188
"http://www.w3.org/XML/1998/namespace", "not a name");
190
id.setLocalName("id");
191
fail("Allowed non-NCNAME ID");
193
catch (IllegalDataException success) {
194
assertNotNull(success.getMessage());
200
public void testCantChangeTypeOfXMLIDAttribute() {
202
Attribute id = new Attribute("xml:id",
203
"http://www.w3.org/XML/1998/namespace", "p2");
206
id.setType(Attribute.Type.CDATA);
207
fail("changed xml:id attribute to CDATA");
209
catch (IllegalDataException success) {
210
assertNotNull(success.getMessage());
212
assertEquals(Attribute.Type.ID, id.getType());
217
public void testCantChangeValueOfXMLIDAttributeToNonNCName() {
219
Attribute id = new Attribute("xml:id",
220
"http://www.w3.org/XML/1998/namespace", "p2");
221
Attribute id2 = new Attribute(id);
223
id.setValue("not a name");
224
fail("Allowed non-name for xml:id");
226
catch (IllegalDataException success) {
227
assertNotNull(success.getMessage());
231
assertEquals(id, id2);
236
public void testXPathRecognizesXmlIDAttributes()
237
throws ParsingException, IOException {
239
Element root = new Element("root");
240
Document doc = new Document(root);
241
Element child = new Element("child");
242
root.appendChild(child);
243
Attribute id = new Attribute("id", "p2");
244
child.addAttribute(id);
245
id.setNamespace("xml", "http://www.w3.org/XML/1998/namespace");
246
Nodes result = doc.query("id('p2')");
247
assertEquals(1, result.size());
248
assertEquals(child, result.get(0));
253
public void testXMLIDTestSuiteFromW3CServer()
254
throws ParsingException, IOException {
256
URL base = new URL("http://www.w3.org/XML/2005/01/xml-id/test-suite.xml");
257
Builder builder = new Builder();
258
Document catalog = builder.build(base.openStream());
259
Element testsuite = catalog.getRootElement();
260
Elements testCatalogs = testsuite.getChildElements("test-catalog");
261
for (int i = 0; i < testCatalogs.size(); i++) {
262
Elements testcases = testCatalogs.get(i).getChildElements("test-case");
263
for (int j = 0; j < testcases.size(); j++) {
264
Element testcase = testcases.get(j);
265
String features = testcase.getAttributeValue("feature");
266
if (features != null && features.indexOf("xml11") >= 0) {
267
continue; // skip test
269
URL testURL = new URL(base, testcase.getFirstChildElement("file-path").getValue() + "/");
270
Element scenario = testcase.getFirstChildElement("scenario");
271
Element input = scenario.getFirstChildElement("input-file");
272
URL inputFile = new URL(testURL, input.getValue());
273
Elements expectedIDs = scenario.getChildElements("id");
274
Document inputDoc = builder.build(inputFile.openStream());
275
Nodes recognizedIDs = getIDs(inputDoc);
276
assertEquals(expectedIDs.size(), recognizedIDs.size());
277
for (int k = 0; k < expectedIDs.size(); k++) {
278
assertEquals(expectedIDs.get(i).getValue(), recognizedIDs.get(i).getValue());
286
public void testXMLIDTestSuite()
287
throws ParsingException, IOException {
289
Builder builder = new Builder();
290
File base = new File("data");
291
base = new File(base, "xmlid");
292
File catalog = new File(base, "catalog.xml");
294
// The test suite needs to be installed separately. If we can't
295
// find the catalog, we just don't run these tests.
296
if (catalog.exists()) {
297
Document doc = builder.build(catalog);
298
Element testsuite = doc.getRootElement();
299
Elements testCatalogs = testsuite.getChildElements("test-catalog");
300
for (int i = 0; i < testCatalogs.size(); i++) {
301
Elements testcases = testCatalogs.get(i).getChildElements("test-case");
302
for (int j = 0; j < testcases.size(); j++) {
303
Element testcase = testcases.get(j);
304
String features = testcase.getAttributeValue("features");
305
if (features != null && features.indexOf("xml11") >= 0) {
306
continue; // skip test
308
File root = new File(base, testcase.getFirstChildElement("file-path").getValue());
309
File inputFile = null;
310
Element scenario = testcase.getFirstChildElement("scenario");
311
Element input = scenario.getFirstChildElement("input");
312
inputFile = new File(root, input.getValue());
313
Elements expectedIDs = scenario.getChildElements("id");
315
Document inputDoc = builder.build(inputFile);
316
Nodes recognizedIDs = getIDs(inputDoc);
317
assertEquals(expectedIDs.size(), recognizedIDs.size());
318
for (int k = 0; k < expectedIDs.size(); k++) {
319
assertEquals(expectedIDs.get(i).getValue(), recognizedIDs.get(i).getValue());
322
catch (ParsingException ex) {
323
System.err.println(inputFile);
324
ex.printStackTrace();
334
private Nodes getIDs(Document doc) {
336
Element root = doc.getRootElement();
337
Nodes list = new Nodes();
343
private void getIDs(Element element, Nodes list) {
345
for (int i = 0; i < element.getAttributeCount(); i++) {
346
Attribute a = element.getAttribute(i);
347
if (a.getType() == Attribute.Type.ID) {
348
// need to sort these into specific order
352
for (int i = 0; i < element.getChildCount(); i++) {
353
Node child = element.getChild(i);
354
if (child instanceof Element) {
355
getIDs((Element) child, list);