blob: a94c09df418327016c2113c66122ead94576e997 [file]
/* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package xmlcursor.checkin;
import org.apache.xmlbeans.*;
import org.apache.xmlbeans.XmlCursor.TokenType;
import org.apache.xmlbeans.XmlCursor.XmlBookmark;
import org.apache.xmlbeans.impl.store.Locale;
import org.apache.xmlbeans.impl.xb.xsdschema.SchemaDocument;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.xml.sax.*;
import org.xml.sax.ext.LexicalHandler;
import org.xml.sax.helpers.AttributesImpl;
import xmlcursor.common.Common;
import javax.xml.namespace.QName;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import java.io.StringReader;
import java.util.*;
import static org.junit.jupiter.api.Assertions.*;
import static xmlcursor.common.BasicCursorTestCase.cur;
import static xmlcursor.common.BasicCursorTestCase.obj;
public class StoreTests {
static String[] _args;
static String _test;
@ParameterizedTest
@ValueSource(strings = {
"<a/>",
"<a x='y'/>",
"<a><b>foo</b></a>",
"<a><b>fo<!--moo-->o<?goof ball?>dsfdf</b></a>",
"<a xmlns='nnn'></a>",
"<a x='y'><!---->x<b/><c p='q'>z</c></a>",
"<a x='y'><!----><b>moo</b><c p='q'></c></a>",
"<a>asa<b/>sdsd<c>aaz</c>adsasd</a>",
"<a><?target value?></a>",
"<n:a xmlns:n='nnn'></n:a>",
"<j:a x='y' p='q' xmlns:j='k'></j:a>",
"<foo xmlns=\"foo.com\"><bar>1</bar></foo>",
"<foo><!--comment--><?target foo?></foo>",
"<foo>a<bar>b</bar>c<bar>d</bar>e</foo>",
"<foo xmlns:x=\"y\"><bar xmlns:x=\"z\"/></foo>",
"<foo x=\"y\" p=\"r\"/>"
})
void testXMLStreamReader(String xml) throws Exception {
XmlObject x1 = XmlObject.Factory.parse(xml);
XmlObject x2;
try (XmlCursor c = x1.newCursor()) {
x2 = XmlObject.Factory.parse(c.newXMLStreamReader());
}
String x1Text = x1.xmlText();
String x2Text = x2.xmlText();
assertEquals(x1Text, x2Text);
}
@Test
void testReplaceContents() throws Exception {
XmlObject xDst = XmlObject.Factory.newInstance();
XmlObject xSrc = XmlObject.Factory.parse("<foo/>");
XmlObject newDst = xDst.set(xSrc);
assertEquals("<foo/>", newDst.xmlText());
xDst = XmlObject.Factory.parse("<bar/>");
xSrc = XmlObject.Factory.parse("<foo/>");
try (XmlCursor c = xDst.newCursor()) {
c.toNextToken();
xDst = c.getObject();
xDst.set(xSrc);
c.toStartDoc();
xDst = c.getObject();
}
assertEquals("<bar><foo/></bar>", xDst.xmlText());
xDst = XmlObject.Factory.parse("<bar x='y'/>");
xSrc = XmlObject.Factory.parse("<foo>moo</foo>");
try (XmlCursor c = xDst.newCursor()) {
c.toNextToken();
c.toNextToken();
xDst = c.getObject();
xDst.set(xSrc);
c.toStartDoc();
xDst = c.getObject();
}
assertEquals("<bar x=\"moo\"/>", xDst.xmlText());
}
@Test
void testSniffing() throws Exception {
XmlObject x;
x = obj("<xoo/>");
Assertions.assertSame(x.schemaType(), XmlBeans.NO_TYPE);
x = obj("<schema xmlns='http://www.w3.org/2001/XMLSchema'/>");
Assertions.assertSame(x.schemaType(), SchemaDocument.type);
x = obj("<schema xmlns='http://www.w3.org/2001/XMLSchema/moo'/>");
Assertions.assertSame(x.schemaType(), XmlBeans.NO_TYPE);
x = obj("<schema xmlns='http://www.w3.org/2001/XMLSchema'/>");
Assertions.assertSame(x.schemaType(), SchemaDocument.type);
x = org.apache.xmlbeans.impl.xb.xsdschema.SchemaDocument.Factory.parse(
"<schema xmlns='http://www.w3.org/2001/XMLSchema'/>");
Assertions.assertSame(x.schemaType(), SchemaDocument.type);
assertThrows(Exception.class, () ->
org.apache.xmlbeans.impl.xb.xsdschema.SchemaDocument.Factory.parse(
"<schema xmlns='http://www.w3.org/2001/XMLSchema/moo'/>")
);
}
@Test
void testCursorStack() throws Exception {
try (XmlCursor c = cur("<foo x='y'/>")) {
c.push();
c.toNextToken();
c.push();
c.toNextToken();
assertTrue(c.isAttr());
c.pop();
assertTrue(c.isStart());
c.pop();
assertTrue(c.isStartdoc());
}
}
@Test
void testImplicitNamespaces() {
Map<String, String> namespaces = new HashMap<>();
namespaces.put("foo", "foo.com");
namespaces.put("bar", "bar.com");
namespaces.put("", "default.com");
XmlOptions options = new XmlOptions();
options.setSaveImplicitNamespaces(namespaces);
XmlObject x = XmlObject.Factory.newInstance();
try (XmlCursor c = x.newCursor()) {
c.toNextToken();
c.beginElement("a", "foo.com");
c.beginElement("b", "default.com");
c.beginElement("c", "bar.com");
}
assertEquals("<foo:a><b><bar:c/></b></foo:a>", x.xmlText(options));
}
private static class Content implements ContentHandler, LexicalHandler {
public void startDocument() {
add("START_DOCUMENT");
}
public void endDocument() {
add("END_DOCUMENT");
}
public void startElement(
String namespaceURI, String localName,
String qName, Attributes atts) {
add("START_ELEMENT");
add(" namespaceURI: " + namespaceURI);
add(" localName: " + localName);
// add( " qName: " + qName );
TreeSet<String> sortedAttrs = new TreeSet<>();
for (int i = 0; i < atts.getLength(); i++) {
String ln = atts.getLocalName(i);
String uri = atts.getURI(i);
String qname = atts.getQName(i);
if (ln.equals("xmlns")) {
continue;
}
if (qname.startsWith("xmlns")) {
continue;
}
// if (ln.equals( "xmlns" ))
// ln = "";
//
// if (uri.equals( "xmlns" ))
// uri = "";
sortedAttrs.add(
uri + "-" + ln + "-" +
atts.getQName(i) + "-" + atts.getType(i) + "-" +
atts.getValue(i));
}
for (String sortedAttr : sortedAttrs) {
add(" Attr: " + sortedAttr);
}
}
public void endElement(
String namespaceURI, String localName, String qName) {
add("END_ELEMENT");
add(" namespaceURI: " + namespaceURI);
add(" localName: " + localName);
// add( " qName: " + qName );
}
public void characters(char[] ch, int start, int length) {
if (length > 0) {
add("CHARACTERS");
add(ch, start, length);
}
}
public void comment(char[] ch, int start, int length) {
add("COMMENT");
add(" Comment: ", ch, start, length);
}
public void processingInstruction(String target, String data) {
add("PROCESSING_INSTRUCTION");
add("target: " + target);
add("data: " + data);
}
public void ignorableWhitespace(char[] ch, int start, int length) {
if (length > 0) {
add("IGNORABLE_WHITESPACE");
add(" whitespace: ", ch, start, length);
}
}
public void startPrefixMapping(String prefix, String uri) {
add("START_PREFIX_MAPPING");
// add( " prefix: " + prefix );
add(" uri: " + uri);
}
public void endPrefixMapping(String prefix) {
add("END_PREFIX_MAPPING");
// add( " prefix: " + prefix );
}
public void startCDATA() {
add("START_CDATA");
}
public void endCDATA() {
add("END_CDATA");
}
public void startDTD(String name, String publicId, String systemId) {
add("START_DTD");
add(" name: " + name);
add(" publicId: " + publicId);
add(" systemId: " + systemId);
}
public void endDTD() {
add("END_DTD");
}
public void startEntity(String name) {
add("START_ENTITY");
add(" name: " + name);
}
public void endEntity(String name) {
add("END_ENTITY");
add(" name: " + name);
}
public void setDocumentLocator(Locator locator) {
// add( "START_DOCUMENT_LOCATOR" );
}
public void skippedEntity(String name) {
add("SKIPPED_ENTITY");
add(" name: " + name);
}
private void add(String s) {
_sb.append(s);
_sb.append("\n");
}
private void add(String s, char[] buf, int off, int cch) {
_sb.append(s);
if (buf != null) {
_sb.append(buf, off, cch);
}
_sb.append("\n");
}
private void add(char[] buf, int off, int cch) {
_sb.append(buf, off, cch);
_sb.append("\n");
}
public boolean equals(Object that) {
return toString().equals(that.toString());
}
public String toString() {
return _sb.toString();
}
private final StringBuilder _sb = new StringBuilder();
}
@ParameterizedTest
@ValueSource(strings = {
"<a xmlns='nnn'></a>",
"<a x='y'><!---->x<b/><c p='q'>z</c></a>",
"<a x='y'><!----><b>moo</b><c p='q'></c></a>",
"<a>asa<b/>sdsd<c>aaz</c>adsasd</a>",
"<a><?target value?></a>",
"<n:a xmlns:n='nnn'></n:a>",
"<j:a x='y' p='q' xmlns:j='k'></j:a>"
})
void testSaxSaver(String xml) throws Exception {
// ME
Content content2 = new Content();
XmlObject x = XmlObject.Factory.parse(xml);
x.save(content2, content2);
// THEM
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
Content content1 = new Content();
xr.setProperty("http://xml.org/sax/properties/lexical-handler", content1);
xr.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
xr.setFeature("http://xml.org/sax/features/namespaces", true);
xr.setFeature("http://xml.org/sax/features/validation", false);
xr.setContentHandler(content1);
InputSource is = new InputSource(new StringReader(xml));
xr.parse(is);
assertEquals(content1, content2);
}
@Test
@Disabled
public void testParsing() throws Exception {
Random r = new Random(1);
for (int i = 0; i < 100000; i++) {
String xml = makeRandomDocument(r);
XmlObject.Factory.parse(xml);
}
}
private void doTestLineNumbers(String xml)
throws Exception {
int line = 1;
int col = 1;
try (XmlCursor c = XmlObject.Factory.parse(
xml, new XmlOptions().setLoadLineNumbers()).
newCursor()) {
for (int i = 0; i < xml.length(); i++) {
char ch = xml.charAt(i);
if (ch == '<' && Character.isLetter(xml.charAt(i + 1))) {
while (!c.currentTokenType().isStart()) {
c.toNextToken();
}
assertTrue(c.currentTokenType().isStart());
XmlLineNumber ln =
(XmlLineNumber)
c.getBookmark(XmlLineNumber.class);
assertNotNull(ln);
assertTrue(ln.getLine() == -1 || ln.getLine() == line);
assertTrue(ln.getColumn() == -1 || ln.getColumn() == col);
assertTrue(ln.getOffset() == -1 || ln.getOffset() == i);
c.toNextToken();
}
if (ch == '\n') {
line++;
col = 1;
} else {
col++;
}
}
}
}
@Test
@Disabled
public void testLineNumbers() throws Exception {
Random r = new Random(1);
for (int i = 0; i < 1000; i++) {
String xml = makeRandomDocument(r);
doTestLineNumbers(xml);
}
}
private static class DocBuilder {
Random r;
StringBuilder sb;
DocBuilder(Random _r, StringBuilder _sb) {
r = _r;
sb = _sb;
}
void append(char ch) {
sb.append(ch);
}
void append(String s) {
sb.append(s);
}
public void whitespace() {
int p = r.nextInt(100);
if (p < 20) {
append('\t');
} else if (p < 40) {
append('\n');
} else {
append(' ');
}
}
void whitespaces() {
for (int i = r.nextInt(8); i > 0; i--) {
whitespace();
}
}
char makeLetter() {
return (char) (((int) 'a') + r.nextInt(26));
}
public void letter() {
append(makeLetter());
}
void charEntity() {
switch (r.nextInt(5)) {
case 0:
append("&lt;");
break;
case 1:
append("&gt;");
break;
case 2:
append("&amp;");
break;
case 3:
append("&apos;");
break;
case 4:
append("&quot;");
break;
}
}
public void text() {
for (int i = r.nextInt(20); i > 0; i--) {
int p = r.nextInt(100);
if (p < 70) {
letter();
} else if (p < 74) {
charEntity();
} else {
whitespace();
}
}
}
String makeNcName() {
StringBuilder name = new StringBuilder();
for (; ; ) {
char ch = makeLetter();
if (ch == 'x' || ch == 'X') {
continue;
}
name.append(ch);
break;
}
for (int i = r.nextInt(20); i > 0; i--) {
name.append(makeLetter());
}
return name.toString();
}
void ncName() {
append(makeNcName());
}
public void comment() {
append("<!--");
text();
append("-->");
}
public void procinst() {
append("<?");
ncName();
if (r.nextInt(100) < 90) {
whitespace();
text();
}
append("?>");
}
void whiteContent() {
for (; ; ) {
int p = r.nextInt(100);
if (p < 20) {
break;
} else if (p < 50) {
whitespaces();
} else if (p < 70) {
comment();
} else {
procinst();
}
}
}
void xmlDecl() {
append("<?xml version=\"1.0\"?>");
}
public void content(int depth) {
for (int i = r.nextInt(10); i > 0; i--) {
switch (r.nextInt(4)) {
case 0:
elementContent(depth + 1);
break;
case 1:
text();
break;
case 2:
comment();
break;
case 3:
procinst();
break;
}
}
}
public void attribute() {
ncName();
if (r.nextInt(100) == 0) {
whitespaces();
}
append('=');
if (r.nextInt(100) == 0) {
whitespaces();
}
char q = r.nextInt(2) == 0 ? '\'' : '"';
append(q);
text();
append(q);
}
void elementContent(int depth) {
// If depth == 0, guarantee an element, otherwise, as depth
// increases, the probablility we'll spit out an element
// gets smaller.
if (r.nextInt(depth + 1) <= 1) {
String name = makeNcName();
append('<');
append(name);
if (r.nextInt(100) == 0) {
whitespaces();
}
HashMap<String, Object> attrs = new HashMap<>();
for (int i = r.nextInt(3); i > 0; i--) {
append(' ');
String aname;
do {
aname = makeNcName();
} while (attrs.containsKey(aname));
attrs.put(aname, null);
append(aname);
if (r.nextInt(100) == 0) {
whitespaces();
}
append('=');
if (r.nextInt(100) == 0) {
whitespaces();
}
char q = r.nextInt(2) == 0 ? '\'' : '"';
append(q);
text();
append(q);
if (r.nextInt(10) == 0) {
whitespaces();
}
}
append('>');
content(depth);
append("</");
append(name);
if (r.nextInt(100) == 0) {
whitespaces();
}
append('>');
}
}
public void document() {
if (r.nextInt(2) == 0) {
xmlDecl();
}
whiteContent();
elementContent(0);
whiteContent();
}
}
private String makeRandomDocument(Random r) {
StringBuilder sb = new StringBuilder();
DocBuilder db = new DocBuilder(r, sb);
db.document();
return sb.toString();
}
private static class MyMark extends XmlBookmark {
}
@Test
void testBookmarks()
throws Exception {
XmlObject x = XmlObject.Factory.parse("<foo x='y'>abcdefg<!---->xy</foo>");
try (XmlCursor c = x.newCursor()) {
MyMark m1 = new MyMark();
c.setBookmark(m1);
c.toNextToken();
MyMark m2 = new MyMark();
c.setBookmark(m2);
c.toNextToken();
MyMark m3 = new MyMark();
c.setBookmark(m3);
c.toNextToken();
MyMark m4 = new MyMark();
c.setBookmark(m4);
c.toNextChar(1);
MyMark m5 = new MyMark();
c.setBookmark(m5);
c.toNextChar(3);
MyMark m6 = new MyMark();
c.setBookmark(m6);
c.toNextToken();
c.toNextToken();
c.toNextToken();
MyMark m7 = new MyMark();
c.setBookmark(m7);
c.toNextToken();
MyMark m8 = new MyMark();
c.setBookmark(m8);
c.toStartDoc();
Assertions.assertSame(c.getBookmark(MyMark.class), m1);
Assertions.assertSame(c.toNextBookmark(MyMark.class), m2);
Assertions.assertSame(c.toNextBookmark(MyMark.class), m3);
Assertions.assertSame(c.toNextBookmark(MyMark.class), m4);
Assertions.assertSame(c.toNextBookmark(MyMark.class), m5);
Assertions.assertSame(c.toNextBookmark(MyMark.class), m6);
Assertions.assertSame(c.toNextBookmark(MyMark.class), m7);
Assertions.assertSame(c.toNextBookmark(MyMark.class), m8);
assertNull(c.toNextBookmark(MyMark.class));
c.toEndDoc();
Assertions.assertSame(c.getBookmark(MyMark.class), m8);
Assertions.assertSame(c.toPrevBookmark(MyMark.class), m7);
Assertions.assertSame(c.toPrevBookmark(MyMark.class), m6);
Assertions.assertSame(c.toPrevBookmark(MyMark.class), m5);
Assertions.assertSame(c.toPrevBookmark(MyMark.class), m4);
Assertions.assertSame(c.toPrevBookmark(MyMark.class), m3);
Assertions.assertSame(c.toPrevBookmark(MyMark.class), m2);
Assertions.assertSame(c.toPrevBookmark(MyMark.class), m1);
assertNull(c.toPrevBookmark(MyMark.class));
}
}
@Test
void testSetName() throws Exception {
XmlObject x = XmlObject.Factory.parse("<foo x='a'/>");
try (XmlCursor c = x.newCursor()) {
c.toNextToken();
c.setName(new QName("bar"));
c.toNextToken();
c.setName(new QName("y"));
}
assertEquals("<bar y=\"a\"/>", x.xmlText());
}
//
// Basic load up a file and iterate through it
//
@Test
void testBasicXml() throws Exception {
try (XmlCursor c = XmlObject.Factory.parse(Common.XML_ATTR_TEXT, null).newCursor()) {
int n = 0;
for (; ; ) {
TokenType t = c.toNextToken();
n++;
if (t == TokenType.NONE) {
break;
}
}
assertEquals(6, n);
}
}
//
// Make sure the tokens going forward the the reverse of the tokens
// going backward
//
@Test
void testConsistentTokenOrder() throws Exception {
ArrayList<TokenType> l = new ArrayList<>();
try (XmlCursor c = XmlObject.Factory.parse(Common.XML_ATTR_TEXT, null).newCursor()) {
do {
// System.err.println(c.currentTokenType());
l.add(c.currentTokenType());
} while (c.toNextToken() != TokenType.NONE);
c.toEndDoc();
// System.err.println("Reversing");
for (int i = l.size() - 1; ; i--) {
// System.err.println(c.currentTokenType());
assertEquals(l.get(i), c.currentTokenType());
if (c.toPrevToken() == TokenType.NONE) {
break;
}
}
}
}
// Make sure you can't insert text before the doc begin going backward
@Test
void testIllegalTextInsert() throws Exception {
try (XmlCursor c = XmlObject.Factory.parse(Common.XML_ATTR_TEXT, null).newCursor()) {
assertThrows(IllegalStateException.class, () -> c.insertChars("Ho ho ho"));
}
}
// Make sure getText works in a basic way
@Test
void testgetText() throws Exception {
try (XmlCursor c = XmlObject.Factory.parse(Common.XML_ATTR_TEXT, null).newCursor()) {
assertEquals("ab", c.getTextValue()); // Doc node
c.toNextToken();
assertEquals("ab", c.getTextValue()); // Doc elem
c.toNextToken();
assertEquals("y", c.getTextValue()); // Attr x
c.toNextToken();
assertEquals("ab", c.getChars()); // Text
c.toNextChar(1);
assertEquals("b", c.getChars()); // Text
c.toNextToken();
assertEquals(0, c.getChars().length()); // End tag
c.toNextToken();
assertEquals(0, c.getChars().length()); // End doc
}
}
//
// Text XMLInputStream support
//
private void doSaverTest(String xml) throws Exception {
try (XmlCursor c = XmlObject.Factory.parse(xml).newCursor()) {
assertEquals(xml, c.xmlText());
}
}
private void doSaveTest(String xml) throws Exception {
doSaverTest(xml);
}
@Test
void testCDATA() throws Exception {
// https://issues.apache.org/jira/browse/XMLBEANS-404
String xml = "<foo>Unable to render embedded object: <![CDATA[>>>>>>>><<<<<<<<<<<]]></foo>";
String expected = "<foo><![CDATA[Unable to render embedded object: >>>>>>>><<<<<<<<<<<]]></foo>";
XmlOptions options = new XmlOptions().setSaveCDataLengthThreshold(0);
try (XmlCursor c = XmlObject.Factory.parse(xml, options).newCursor()) {
assertEquals(expected, c.xmlText(options));
}
}
@Test
void testSaving() throws Exception {
doSaveTest("<foo xmlns=\"foo.com\"><bar>1</bar></foo>");
doSaveTest("<foo><!--comment--><?target foo?></foo>");
doSaveTest("<foo>a<bar>b</bar>c<bar>d</bar>e</foo>");
doSaveTest("<foo xmlns:x=\"y\"><bar xmlns:x=\"z\"/></foo>");
doSaveTest("<foo x=\"y\" p=\"r\"/>");
String s = "<foo>aaa</foo>bbb";
s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s;
s = "<bar>xxxx" + s + "</bar>";
doSaveTest(s);
XmlObject x =
XmlObject.Factory.parse("<foo xmlns:a='a.com'><bar xmlns:a='b.com'/></foo>");
try (XmlCursor c = x.newCursor()) {
c.toFirstChild();
c.toFirstChild();
assertEquals("<bar xmlns:a=\"b.com\"/>", c.xmlText());
x = XmlObject.Factory.parse("<foo xmlns:a='a.com'><bar/></foo>");
}
try (XmlCursor c = x.newCursor()) {
c.toFirstChild();
c.toFirstChild();
assertEquals("<bar xmlns:a=\"a.com\"/>", c.xmlText());
}
}
private XmlCursor navDoc(XmlObject x, String dirs) {
return navCursor(x.newCursor(), dirs);
}
private XmlCursor navNewCursor(XmlCursor c, String dirs) {
return navCursor(c.newCursor(), dirs);
}
//
// Format:
//
// ( [-][N] type ) *
//
// type:
//
// c - character
// t - token
// p - parent element
// s - sibling element
// d - descendent (child) element
// r - end of the doc (root)
// b - begin of the doc
//
private XmlCursor navCursor(XmlCursor c, String dirs) {
int n = 0;
boolean prev = false;
for (int i = 0; i < dirs.length(); i++) {
char ch = dirs.charAt(i);
if (ch == '-') {
prev = !prev;
continue;
} else if (ch >= '0' && ch <= '9') {
n = n * 10 + (ch - '0');
continue;
}
if (n == 0) {
n = 1;
}
if (ch == 'c') {
if (prev) {
assertEquals(c.toPrevChar(n), n);
} else {
assertEquals(c.toNextChar(n), n);
}
} else if (ch == 't') {
while (n-- > 0) {
if (prev) {
assertNotSame(c.toPrevToken(), TokenType.NONE);
} else {
assertNotSame(c.toNextToken(), TokenType.NONE);
}
}
} else if (ch == 'p') {
assertFalse(prev);
while (n-- > 0) {
assertTrue(c.toParent());
}
} else if (ch == 'r') {
assertFalse(prev);
assertEquals(1, n);
c.toEndDoc();
} else if (ch == 'b') {
assertFalse(prev);
assertEquals(1, n);
c.toStartDoc();
} else if (ch == 's') {
while (n-- > 0) {
if (prev) {
assertTrue(c.toPrevSibling());
} else {
assertTrue(c.toNextSibling());
}
}
} else if (ch == 'd') {
assertFalse(prev);
while (n-- > 0) {
assertTrue(c.toFirstChild());
}
} else {
Assertions.fail();
}
n = 0;
prev = false;
}
return c;
}
@Test
void testOps() throws Exception {
XmlObject x, x2, y;
XmlBookmark anno;
//
x = XmlObject.Factory.parse("<foo>abcdef</foo>");
try (XmlCursor cFrom = navDoc(x, "d");
XmlCursor cTo = navNewCursor(cFrom, "")) {
assertTrue(cFrom.moveXml(cTo));
cFrom.insertChars("[FROM]");
cTo.insertChars("[TO]");
}
XmlOptions options = new XmlOptions();
options.setSaveSyntheticDocumentElement(new QName(null, "bar"));
assertTrue(x.xmlText(options).equals("<bar>[TO]<foo>abcdef</foo>[FROM]</bar>") ||
x.xmlText(options).equals("<bar>[FROM]<foo>abcdef</foo>[TO]</bar>"));
//
x = XmlObject.Factory.parse("<foo>abcdef</foo>");
try (XmlCursor cFrom = navDoc(x, "d");
XmlCursor cTo = navNewCursor(cFrom, "ttt")) {
assertTrue(cFrom.moveXml(cTo));
cFrom.insertChars("[FROM]");
cTo.insertChars("[TO]");
}
assertTrue(x.xmlText(options).equals("<bar><foo>abcdef</foo>[FROM][TO]</bar>") ||
x.xmlText(options).equals("<bar><foo>abcdef</foo>[TO][FROM]</bar>"));
//
x = XmlObject.Factory.parse("<foo>abcdef</foo>");
try (XmlCursor cFrom = navDoc(x, "d");
XmlCursor cTo = navNewCursor(cFrom, "t3c")) {
assertFalse(cFrom.moveXml(cTo));
cFrom.insertChars("[FROM]");
cTo.insertChars("[TO]");
}
assertEquals("<bar>[FROM]<foo>abc[TO]def</foo></bar>", x.xmlText(options));
//
x = XmlObject.Factory.parse("<r><a>xyz</a><b>pqr</b></r>");
try (XmlCursor cFrom = navDoc(x, "dd");
XmlCursor cTo = navNewCursor(cFrom, "r-1t")) {
assertTrue(cFrom.moveXml(cTo));
cFrom.insertChars("[FROM]");
cTo.insertChars("[TO]");
}
assertEquals("<r>[FROM]<b>pqr</b><a>xyz</a>[TO]</r>", x.xmlText());
//
x = XmlObject.Factory.parse("<r><a>xyz</a><b>pqr</b>AB</r>");
try (XmlCursor cFrom = navDoc(x, "dd");
XmlCursor cTo = navNewCursor(cFrom, "r-1t-1c")) {
assertTrue(cFrom.moveXml(cTo));
cFrom.insertChars("[FROM]");
cTo.insertChars("[TO]");
}
assertEquals("<r>[FROM]<b>pqr</b>A<a>xyz</a>[TO]B</r>", x.xmlText());
//
x = XmlObject.Factory.parse("<r><a>xyz</a><b>pqr</b>AB</r>");
try (XmlCursor cFrom = navDoc(x, "dd");
XmlCursor cTo = navNewCursor(cFrom, "stc")) {
assertTrue(cFrom.moveXml(cTo));
cFrom.insertChars("[FROM]");
cTo.insertChars("[TO]");
}
assertEquals("<r>[FROM]<b>p<a>xyz</a>[TO]qr</b>AB</r>", x.xmlText());
//
x = XmlObject.Factory.parse("<r><a>xyz</a><b>pqr</b>AB</r>");
try (XmlCursor cFrom = navDoc(x, "dd");
XmlCursor cTo = navDoc(x, "d")) {
assertTrue(cFrom.moveXml(cTo));
cFrom.insertChars("[FROM]");
cTo.insertChars("[TO]");
}
testTextFrag(x.xmlText(), "<a>xyz</a>[TO]<r>[FROM]<b>pqr</b>AB</r>");
//
x = XmlObject.Factory.parse("<r><a>xyz</a><b>pqr</b>AB</r>");
try (XmlCursor cFrom = navDoc(x, "dd");
XmlCursor cTo = navDoc(x, "r")) {
assertTrue(cFrom.moveXml(cTo));
cFrom.insertChars("[FROM]");
cTo.insertChars("[TO]");
}
assertEquals("<bar><r>[FROM]<b>pqr</b>AB</r><a>xyz</a>[TO]</bar>", x.xmlText(options));
//
x = XmlObject.Factory.parse("<r><a>xyz</a></r>");
x2 = XmlObject.Factory.parse("<s></s>");
try (XmlCursor cFrom = navDoc(x, "dd");
XmlCursor cTo = navDoc(x2, "dt")) {
assertTrue(cFrom.moveXml(cTo));
cFrom.insertChars("[FROM]");
cTo.insertChars("[TO]");
}
assertEquals("<r>[FROM]</r>", x.xmlText());
assertEquals("<s><a>xyz</a>[TO]</s>", x2.xmlText());
//
x = XmlObject.Factory.parse("<r><a>pq</a><b></b></r>");
try (XmlCursor cFrom = navDoc(x, "dd");
XmlCursor cTo = navDoc(x, "ddst");
XmlCursor cTemp = navDoc(x, "ddt1c")) {
assertTrue(cFrom.moveXml(cTo));
cFrom.insertChars("[FROM]");
cTo.insertChars("[TO]");
cTemp.insertChars("[TEMP]");
}
assertEquals("<r>[FROM][TEMP]<b><a>pq</a>[TO]</b></r>", x.xmlText());
//
x = XmlObject.Factory.parse("<foo>abcdef</foo>");
try (XmlCursor cFrom = navDoc(x, "2t2c");
XmlCursor cTo = navNewCursor(cFrom, "-1c")) {
cFrom.moveChars(2, cTo);
cFrom.insertChars("[FROM]");
cTo.insertChars("[TO]");
}
assertEquals("<foo>acd[TO]b[FROM]ef</foo>", x.xmlText());
//
x = XmlObject.Factory.parse("<foo>abcdef</foo>");
try (XmlCursor cFrom = navDoc(x, "2t2c");
XmlCursor cTo = navNewCursor(cFrom, "3c")) {
cFrom.moveChars(2, cTo);
cFrom.insertChars("[FROM]");
cTo.insertChars("[TO]");
}
assertEquals("<foo>ab[FROM]ecd[TO]f</foo>", x.xmlText());
//
x = XmlObject.Factory.parse("<bar><foo>abcdef</foo><foo>123456</foo></bar>");
try (XmlCursor cFrom = navDoc(x, "3t2c");
XmlCursor cTo = navNewCursor(cFrom, "3t3c")) {
cFrom.moveChars(2, cTo);
cFrom.insertChars("[FROM]");
cTo.insertChars("[TO]");
}
assertEquals("<bar><foo>ab[FROM]ef</foo><foo>123cd[TO]456</foo></bar>", x.xmlText());
//
x = XmlObject.Factory.parse("<bar><foo>abcdef</foo><foo>123456</foo></bar>");
try (XmlCursor cFrom = navDoc(x, "2d");
XmlCursor cTo = navDoc(x, "2dst2c")) {
assertTrue(cFrom.copyXml(cTo));
cFrom.insertChars("[FROM]");
cTo.insertChars("[TO]");
}
assertEquals(x.xmlText(), "<bar>[FROM]<foo>abcdef</foo><foo>12" +
"<foo>abcdef</foo>[TO]3456</foo></bar>");
//
x = XmlObject.Factory.parse("<r><a>xyz</a></r>");
x2 = XmlObject.Factory.parse("<s></s>");
try (XmlCursor cFrom = navDoc(x, "dd");
XmlCursor cTo = navDoc(x2, "dt")) {
assertTrue(cFrom.copyXml(cTo));
cFrom.insertChars("[FROM]");
cTo.insertChars("[TO]");
}
assertEquals("<r>[FROM]<a>xyz</a></r>", x.xmlText());
assertEquals("<s><a>xyz</a>[TO]</s>", x2.xmlText());
//
x = XmlObject.Factory.parse(
"<bar><foo>abcdef</foo>blah<foo>123456</foo></bar>");
try (XmlCursor cFrom = navDoc(x, "2d");
XmlCursor cTo = navDoc(x, "2dst2c")) {
assertTrue(cFrom.copyXml(cTo));
cFrom.insertChars("[FROM]");
cTo.insertChars("[TO]");
}
assertEquals(x.xmlText(), "<bar>[FROM]<foo>abcdef</foo>blah<foo>12" +
"<foo>abcdef</foo>[TO]3456</foo></bar>");
//
x = XmlObject.Factory.parse(
"<bar><foo x='y'>abcdef</foo><foo>123456</foo>7890</bar>");
try (XmlCursor cFrom = navDoc(x, "2dt");
XmlCursor cTo = navDoc(x, "2dst");
XmlCursor cTemp = navDoc(x, "2dst3c");
XmlCursor cTemp2 = navDoc(x, "2ds3t2c")) {
assertTrue(cFrom.copyXml(cTo));
cTemp.insertChars("[TEMP]");
cTemp2.insertChars("[TEMP2]");
}
assertEquals(x.xmlText(), "<bar><foo x=\"y\">abcdef</foo>" +
"<foo x=\"y\">123[TEMP]456</foo>78[TEMP2]90</bar>");
//
x = XmlObject.Factory.parse(
"<bar>xy<foo x='y'>abcdef</foo>pqr<foo>123456</foo></bar>");
try (XmlCursor cFrom = navDoc(x, "2d");
XmlCursor cTo = navDoc(x, "2ds-2c")) {
assertTrue(cFrom.removeXml());
cFrom.insertChars("[FROM]");
cTo.insertChars("[TO]");
}
assertEquals("<bar>xy[FROM]p[TO]qr<foo>123456</foo></bar>", x.xmlText());
//
x = XmlObject.Factory.parse(
"<bar>xy<foo x='y'>abcdef</foo>pqr<foo>123456</foo></bar>");
try (XmlCursor cFrom = navDoc(x, "2d2t2c");
XmlCursor cTo = navDoc(x, "2d2t5c")) {
cFrom.removeChars(2);
cFrom.insertChars("[FROM]");
cTo.insertChars("[TO]");
}
assertEquals(x.xmlText(), "<bar>xy<foo x=\"y\">ab[FROM]e[TO]f" +
"</foo>pqr<foo>123456</foo></bar>");
//
x = XmlObject.Factory.parse("<bar><!---->abc</bar>");
try (XmlCursor cFrom = navDoc(x, "tt");
XmlCursor cTo = navDoc(x, "tttc")) {
assertTrue(cFrom.removeXml());
cFrom.insertChars("[FROM]");
cTo.insertChars("[TO]");
}
assertEquals("<bar>[FROM]a[TO]bc</bar>", x.xmlText());
//
x = XmlObject.Factory.newInstance();
try (XmlCursor cTo = navDoc(x, "t")) {
cTo.insertElement("boo");
cTo.toPrevToken();
cTo.insertElement("moo");
cTo.toPrevToken();
cTo.insertElement("goo");
}
assertEquals("<boo><moo><goo/></moo></boo>", x.xmlText());
//
x = XmlObject.Factory.newInstance();
try (XmlCursor cTo = navDoc(x, "t")) {
cTo.insertElement("boo");
cTo.toPrevToken();
cTo.insertElement("moo");
cTo.toPrevToken();
cTo.insertAttributeWithValue("x", "y");
}
assertEquals("<boo><moo x=\"y\"/></boo>", x.xmlText());
//
x = XmlObject.Factory.parse("<bar x='y'>abc</bar>");
try (XmlCursor cTo = navDoc(x, "tt")) {
cTo.insertAttributeWithValue("p", "q");
}
assertEquals("<bar p=\"q\" x=\"y\">abc</bar>", x.xmlText());
// Text XmlBookmark
x = XmlObject.Factory.parse("<r><foo>abc</foo><bar></bar></r>");
try (XmlCursor cFrom = navDoc(x, "tt");
XmlCursor cTo = navDoc(x, "6t")) {
anno = new Anno();
cFrom.setBookmark(anno);
assertTrue(cFrom.moveXml(cTo));
cFrom.insertChars("[FROM]");
cTo.insertChars("[TO]");
try (XmlCursor c = anno.createCursor()) {
c.insertChars("[ANNO]");
}
}
assertEquals("<r>[FROM]<bar>[ANNO]<foo>abc</foo>[TO]</bar></r>", x.xmlText());
// Test content ops
x = XmlObject.Factory.parse("<foo x='y'>abc</foo>");
y = XmlObject.Factory.newInstance();
try (XmlCursor d = y.newCursor()) {
d.toNextToken();
try (XmlCursor c = x.newCursor()) {
c.moveXmlContents(d);
}
}
assertEquals("<foo x=\"y\">abc</foo>", y.xmlText());
x = XmlObject.Factory.parse("<bar><foo x='y'>abc</foo></bar>");
y = XmlObject.Factory.newInstance();
try (XmlCursor c = x.newCursor();
XmlCursor d = y.newCursor()) {
c.toNextToken();
d.toNextToken();
c.moveXmlContents(d);
}
assertEquals("<foo x=\"y\">abc</foo>", y.xmlText());
x = XmlObject.Factory.parse("<bar><foo x='y'>abc</foo></bar>");
try (XmlCursor c = x.newCursor()) {
c.toNextToken();
c.removeXmlContents();
}
assertEquals("<bar/>", x.xmlText());
x = XmlObject.Factory.parse("<foo x='y'>abc</foo>");
y = XmlObject.Factory.newInstance();
try (XmlCursor d = y.newCursor();
XmlCursor e = x.newCursor()) {
d.toNextToken();
e.copyXmlContents(d);
}
assertEquals("<foo x=\"y\">abc</foo>", y.xmlText());
}
private static class Anno extends XmlBookmark {
}
@Test
void testSave() throws Exception {
XmlObject x;
XmlOptions options;
//
x = XmlObject.Factory.parse("<foo>abcdef</foo>");
assertEquals("<foo>abcdef</foo>", x.xmlText());
//
x = XmlObject.Factory.parse("<foo>a&lt;b&amp;c</foo>");
assertEquals("<foo>a&lt;b&amp;c</foo>", x.xmlText());
//
x = XmlObject.Factory.parse("<foo></foo>");
try (XmlCursor cTo = navDoc(x, "dt")) {
cTo.insertChars("&<");
}
assertEquals("<foo>&amp;&lt;</foo>", x.xmlText());
//
x = XmlObject.Factory.parse("<foo><boo>bar</boo></foo>");
try (XmlCursor cTo = navDoc(x, "dt")) {
assertEquals("<boo>bar</boo>", cTo.xmlText());
}
//
x = XmlObject.Factory.parse("<foo><boo x=\"y\">bar</boo></foo>");
try (XmlCursor cTo = navDoc(x, "dt")) {
assertEquals("<boo x=\"y\">bar</boo>", cTo.xmlText());
}
// Tests fragment saving and loading
x = XmlObject.Factory.parse("<foo>Eric</foo>");
try (XmlCursor cTo = navDoc(x, "dt")) {
x = XmlObject.Factory.parse(cTo.xmlText());
}
try (XmlCursor cTo = navDoc(x, "")) {
assertEquals("Eric", cTo.getTextValue());
}
// test save where I replace the name of an element
x = XmlObject.Factory.parse("<foo>Eric</foo>");
options = new XmlOptions();
options.setSaveSyntheticDocumentElement(new QName(null, "bar"));
try (XmlCursor cTo = navDoc(x, "d")) {
x = XmlObject.Factory.parse(cTo.xmlText(options));
}
try (XmlCursor cTo = navDoc(x, "")) {
assertEquals("<bar>Eric</bar>", cTo.xmlText());
}
// test save where I replace the name of the document
x = XmlObject.Factory.parse("<foo>Eric</foo>");
try (XmlCursor cTo = navDoc(x, "")) {
options = new XmlOptions();
options.setSaveSyntheticDocumentElement(new QName(null, "bar"));
x = XmlObject.Factory.parse(cTo.xmlText(options));
}
try (XmlCursor cTo = navDoc(x, "")) {
assertEquals("<bar><foo>Eric</foo></bar>", cTo.xmlText());
}
x = XmlObject.Factory.parse("<a xmlns='foo'/>");
try (XmlCursor c = x.newCursor()) {
c.toFirstContentToken();
c.toFirstContentToken();
c.insertElement("b");
c.toPrevSibling();
assertEquals("b", c.getName().getLocalPart());
assertEquals(0, c.getName().getNamespaceURI().length());
x = XmlObject.Factory.parse(x.xmlText());
}
try (XmlCursor c = x.newCursor()) {
c.toFirstContentToken();
c.toFirstContentToken();
assertEquals("b", c.getName().getLocalPart());
assertEquals(0, c.getName().getNamespaceURI().length());
}
}
private void testTextFrag(String actual, String expected) {
String pre = "<xml-fragment>";
String post = "</xml-fragment>";
assertTrue(actual.startsWith(pre));
assertTrue(actual.endsWith(post));
assertEquals(expected, actual.substring(
pre.length(), actual.length() - post.length()));
}
@Test
void testSaveFrag() {
XmlObject x;
x = XmlObject.Factory.newInstance();
try (XmlCursor c = x.newCursor()) {
c.toNextToken();
c.insertChars("Eric");
}
testTextFrag(x.xmlText(), "Eric");
//
x = XmlObject.Factory.newInstance();
try (XmlCursor c = x.newCursor()) {
c.toNextToken();
c.insertComment("");
c.insertChars("x");
}
testTextFrag(x.xmlText(), "<!---->x");
//
x = XmlObject.Factory.newInstance();
try (XmlCursor c = x.newCursor()) {
c.toNextToken();
c.insertElement("foo");
c.insertChars("x");
}
testTextFrag(x.xmlText(), "<foo/>x");
//
x = XmlObject.Factory.newInstance();
try (XmlCursor c = x.newCursor()) {
c.toNextToken();
c.insertElement("foo");
c.insertElement("bar");
}
testTextFrag(x.xmlText(), "<foo/><bar/>");
}
@Test
void testLoad() throws Exception {
XmlObject x;
XmlOptions options = new XmlOptions();
options.setLoadReplaceDocumentElement(null);
x =
XmlObject.Factory.parse(
"<bar p='q' x='y'>ab<foo>xy</foo>cd</bar>", options);
try (XmlCursor c = navDoc(x, "t")) {
Assertions.assertSame(c.currentTokenType(), TokenType.ATTR);
}
String open = "xmlns:open='http://www.openuri.org/fragment'";
x =
XmlObject.Factory.parse(
"<open:fragment p='q' x='y' " + open +
">ab<foo>xy</foo>cd</open:fragment>");
try (XmlCursor c = navDoc(x, "t")) {
Assertions.assertSame(c.currentTokenType(), TokenType.ATTR);
}
}
@Test
void testCompare() throws Exception {
XmlObject x;
// Forward navigation
x = XmlObject.Factory.parse("<bar p='q' x='y'>ab<foo>xy</foo>cd</bar>");
try (XmlCursor cFrom = navDoc(x, "");
XmlCursor cTo = navDoc(x, "")) {
for (; ; ) {
assertEquals(0, cFrom.comparePosition(cTo));
assertTrue(cFrom.isAtSamePositionAs(cTo));
TokenType tt = cFrom.currentTokenType();
if (tt == TokenType.ENDDOC) {
break;
} else if (tt == TokenType.TEXT) {
cFrom.toNextChar(1);
cTo.toNextChar(1);
} else {
cFrom.toNextToken();
cTo.toNextToken();
}
}
}
// Backward navigation
x = XmlObject.Factory.parse("<bar p='q' x='y'>ab<foo>xy</foo>cd</bar>");
try (XmlCursor cFrom = navDoc(x, "r");
XmlCursor cTo = navDoc(x, "r")) {
for (; ; ) {
assertEquals(0, cFrom.comparePosition(cTo));
assertTrue(cFrom.isAtSamePositionAs(cTo));
if (cFrom.toPrevChar(1) == 1) {
cTo.toPrevChar(1);
} else if (cFrom.toPrevToken() != TokenType.NONE) {
cTo.toPrevToken();
} else {
break;
}
}
}
//
x = XmlObject.Factory.parse(
"<bar p='q' x='y'>ab<foo>xy</foo>c<f y='x'>xy</f>d</bar>");
try (XmlCursor cFrom = navDoc(x, "")) {
for (; ; ) {
boolean passed = false;
try (XmlCursor cTo = navDoc(x, "")) {
for (; ; ) {
if (cTo.isAtSamePositionAs(cFrom)) {
assertFalse(passed);
passed = true;
} else if (cTo.isLeftOf(cFrom)) {
assertFalse(passed);
} else {
assertTrue(passed);
assertTrue(cTo.isRightOf(cFrom));
}
if (cTo.toNextChar(1) != 1) {
if (cTo.toNextToken() == TokenType.ENDDOC) {
break;
}
}
}
}
if (cFrom.toNextChar(1) != 1) {
if (cFrom.toNextToken() == TokenType.ENDDOC) {
break;
}
}
}
}
}
@Test
void testAttrSetter() throws Exception {
XmlObject x = XmlObject.Factory.parse("<foo/>");
try (XmlCursor c = x.newCursor()) {
c.toNextToken();
c.setAttributeText(new QName(null, "x"), "hardehar");
}
assertEquals("<foo x=\"hardehar\"/>", x.xmlText());
}
@Test
void testNavigation() throws Exception {
XmlObject x = XmlObject.Factory.parse("<a><x/><y/><z/></a>");
try (XmlCursor c = x.newCursor()) {
assertFalse(c.toNextSibling());
assertFalse(c.toPrevSibling());
assertFalse(c.toFirstAttribute());
assertFalse(c.toLastAttribute());
c.toNextToken();
c.toNextToken();
assertTrue(c.toNextSibling());
assertEquals("y", c.getName().getLocalPart());
assertTrue(c.toNextSibling());
assertEquals("z", c.getName().getLocalPart());
assertFalse(c.toNextSibling());
}
x = XmlObject.Factory.parse("<a p='q' m='n'><x/><y/><z/></a>");
try (XmlCursor c = x.newCursor()) {
c.toNextToken();
c.toNextToken();
assertTrue(c.currentTokenType().isAttr());
assertFalse(c.toPrevSibling());
assertTrue(c.currentTokenType().isAttr());
assertTrue(c.toNextSibling());
assertEquals("x", c.getName().getLocalPart());
c.toEndDoc();
c.toPrevToken();
assertTrue(c.toPrevSibling());
assertEquals("z", c.getName().getLocalPart());
assertTrue(c.toPrevSibling());
assertEquals("y", c.getName().getLocalPart());
assertTrue(c.toPrevSibling());
assertEquals("x", c.getName().getLocalPart());
assertFalse(c.toPrevSibling());
c.toEndDoc();
c.toPrevToken();
assertTrue(c.toParent());
assertEquals("a", c.getName().getLocalPart());
c.toEndDoc();
assertTrue(c.toParent());
assertTrue(c.currentTokenType().isStartdoc());
}
x = XmlObject.Factory.parse("<a>moo<!---->foo</a>");
try (XmlCursor c = x.newCursor()) {
c.toStartDoc();
c.toNextToken();
c.toNextToken();
c.toNextToken();
assertTrue(c.toParent());
assertEquals("a", c.getName().getLocalPart());
c.toStartDoc();
c.toNextToken();
c.toNextToken();
c.toNextToken();
c.toNextToken();
assertTrue(c.toParent());
assertEquals("a", c.getName().getLocalPart());
c.toStartDoc();
c.toNextToken();
c.toNextToken();
c.toNextToken();
c.toNextToken();
c.toNextChar(2);
assertTrue(c.toParent());
assertEquals("a", c.getName().getLocalPart());
}
x = XmlObject.Factory.parse("<foo>early<bar>text<char>zap</char></bar></foo>");
try (XmlCursor c = x.newCursor()) {
c.toNextToken();
c.toNextToken();
assertTrue(c.toFirstChild());
assertEquals("zap", c.getTextValue());
}
}
@Test
void testGetName() throws Exception {
XmlObject x = XmlObject.Factory.parse("<a x='y'>eric<!----><?moo?></a>");
try (XmlCursor c = x.newCursor()) {
assertNull(c.getName());
assertFalse(c.toNextToken().isNone());
assertEquals("a", c.getName().getLocalPart());
assertEquals(0, c.getName().getNamespaceURI().length());
assertFalse(c.toNextToken().isNone());
assertEquals("x", c.getName().getLocalPart());
assertEquals(0, c.getName().getNamespaceURI().length());
assertFalse(c.toNextToken().isNone());
assertNull(c.getName());
assertFalse(c.toNextToken().isNone());
assertNull(c.getName());
assertFalse(c.toNextToken().isNone());
assertEquals("moo", c.getName().getLocalPart());
assertEquals(0, c.getName().getNamespaceURI().length());
assertFalse(c.toNextToken().isNone());
assertNull(c.getName());
assertFalse(c.toNextToken().isNone());
assertNull(c.getName());
assertTrue(c.toNextToken().isNone());
}
}
@Test
void testGetChars() throws Exception {
XmlObject x = XmlObject.Factory.parse("<foo>abcdefghijkl</foo>");
try (XmlCursor c = x.newCursor()) {
c.toNextToken();
c.toNextToken();
c.toNextChar(2);
char[] buf = new char[3];
int n = c.getChars(buf, 0, 400);
assertEquals(3, n);
assertEquals('c', buf[0]);
assertEquals('d', buf[1]);
assertEquals('e', buf[2]);
}
}
@Test
void testNamespaceSubstitution() throws Exception {
HashMap<String, String> subs = new HashMap<>();
subs.put("foo", "moo");
subs.put("a", "b");
XmlOptions options = new XmlOptions();
options.setLoadSubstituteNamespaces(subs);
XmlObject x = XmlObject.Factory.parse("<a xmlns='foo' xmlns:a='a' a:x='y'/>", options);
try (XmlCursor c = x.newCursor()) {
c.toNextToken();
assertEquals("moo", c.getName().getNamespaceURI());
c.toNextToken();
assertEquals("moo", c.getName().getNamespaceURI());
c.toNextToken();
assertEquals("b", c.getName().getNamespaceURI());
c.toNextToken();
assertEquals("b", c.getName().getNamespaceURI());
}
}
@Test
void testNamespaceInsertion() {
XmlObject x = XmlObject.Factory.newInstance();
try (XmlCursor c = x.newCursor()) {
c.toNextToken();
c.insertElement("foo", "http://p.com");
c.toPrevToken();
c.insertNamespace("p", "http://p.com");
}
assertEquals("<p:foo xmlns:p=\"http://p.com\"/>", x.xmlText());
}
private void dotestParser(String xml, String xmlResult)
throws Exception {
XmlObject x = XmlObject.Factory.parse(xml);
String result = x.xmlText();
assertEquals(xmlResult, result);
}
private void dotestParserErrors(String xml) {
assertThrows(Throwable.class, () -> XmlObject.Factory.parse(xml));
}
@Test
void testNil() throws Exception {
XmlObject x = noNamespace.CanBeNilDocument.Factory.parse("<canBeNil/>");
try (XmlCursor c = x.newCursor()) {
c.toFirstChild();
XmlObject fc = c.getObject();
assertFalse(fc.isNil());
fc.setNil();
assertTrue(fc.isNil());
assertEquals("<canBeNil xsi:nil=\"true\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"/>", x.xmlText());
c.toNextToken();
assertTrue(c.isAttr());
c.removeXml();
assertEquals("<canBeNil/>", x.xmlText());
assertFalse(fc.isNil());
}
}
@Test
void testParser() throws Exception {
dotestParserErrors("<hee yee='five'><haw>66</haw></any>");
dotestParserErrors("<foo></moo>");
dotestParserErrors("<a><foo></moo></a>");
dotestParserErrors("");
dotestParserErrors(" ");
dotestParserErrors("har");
dotestParserErrors("<!-- comment -->");
dotestParserErrors("<?moo?>");
dotestParserErrors("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
dotestParserErrors("<a$/>");
dotestParserErrors("<foo a='<'></foo>");
dotestParserErrors("<foo a></foo>");
dotestParserErrors("<foo>");
dotestParserErrors("</foo>");
dotestParserErrors("<foo><!-- -- --></foo>");
dotestParserErrors("<foo><!-- ---></foo>");
dotestParser("<a b=\"x\n\ny\"/>", "<a b=\"x y\"/>");
}
@Test
void testSaxParser() throws Exception {
String xml = "<a x='y'><!---->x<b/><c p='q'>z</c></a>";
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser sp = spf.newSAXParser();
XMLReader xr = sp.getXMLReader();
InputSource is = new InputSource(new StringReader(xml));
XmlSaxHandler sh = XmlObject.Factory.newXmlSaxHandler();
xr.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
xr.setFeature("http://xml.org/sax/features/namespaces", true);
xr.setFeature("http://xml.org/sax/features/validation", false);
xr.setContentHandler(sh.getContentHandler());
xr.setProperty("http://xml.org/sax/properties/lexical-handler", sh.getLexicalHandler());
xr.parse(is);
XmlObject x1 = sh.getObject();
XmlObject x2 = XmlObject.Factory.parse(xml);
assertEquals(x1.xmlText(), x2.xmlText());
}
@Test
void testSaxHandlerIdDetection() throws SAXException{
final XmlOptions emptyXmlOptions = new XmlOptions();
final String schemaUri = "http://example.com/schema";
final Locale loc = Locale.getLocale(null, null);
final AttributesImpl attrs = new AttributesImpl();
// The QName must be "id" as that's now enough for an attribute to be treated as an ID
attrs.addAttribute(
schemaUri,
"localIgnored",
"id",
"CDATA",
"anId"
);
loc.getSchemaTypeLoader().newXmlSaxHandler(null, emptyXmlOptions);
ContentHandler xmlSaxHandler = Locale.newSaxHandler(
loc.getSchemaTypeLoader(),
null,
emptyXmlOptions
).getContentHandler();
xmlSaxHandler.startElement(
schemaUri,
"localIgnored",
"sa:someName",
attrs
);
}
@Test
void testAdditionalNamespaces() throws Exception {
String xml = "<a xmlns:a='aNS'><a:b/></a>";
Map<String, String> map = new LinkedHashMap<>();
map.put("b", "bNS");
map.put("c", "cNS");
map.put("a", "not-aNS");
XmlOptions options = new XmlOptions();
options.setLoadAdditionalNamespaces(map);
XmlObject x = XmlObject.Factory.parse(xml, options);
// 'a' prefix namespace is not remapped
xml = "<a xmlns='aNS'><b/></a>";
map = new LinkedHashMap<>();
map.put("b", "bNS");
map.put("c", "cNS");
map.put("", "not-aNS");
options = new XmlOptions();
options.setLoadAdditionalNamespaces(map);
x = XmlObject.Factory.parse(xml, options);
// default namespace is not remapped
String expect = "<a xmlns=\"aNS\" xmlns:b=\"bNS\" xmlns:c=\"cNS\"><b/></a>";
assertEquals(expect, x.xmlText());
}
}