blob: 2d78a7f99155c73726e2290ffe5bcc051302323c [file] [log] [blame]
/* 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.xpath.complex.detailed;
import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import tools.util.JarUtil;
import xmlcursor.common.BasicCursorTestCase;
import xmlcursor.xpath.common.XPathCommon;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Verifies XPath impl using examples from
* http://www.zvon.org/xxl/XPathTutorial/Output/example1.html
* includes expanded notations as well
*
*/
@RunWith(Parameterized.class)
public class XPathTest extends BasicCursorTestCase {
@Parameter
public int dataset;
@Parameter(value = 1)
public String xpath;
@Parameter(value = 2)
public String[] expected = null;
@Parameterized.Parameters(name = "{index}: zvon{0}.xml {1}")
public static Collection<Object[]> data() {
final List<Object[]> data = new ArrayList<>();
add(data, 1, "/AAA", "<AAA><BBB/><CCC/><BBB/><BBB/><DDD><BBB/></DDD><CCC/></AAA>");
add(data, 1, "/AAA/CCC", "<CCC/>", "<CCC/>");
add(data, 1, "/AAA/DDD/BBB", "<BBB/>");
add(data, 2, "//BBB", "<BBB/>", "<BBB/>", "<BBB/>", "<BBB/>", "<BBB/>");
add(data, 2, "//DDD/BBB", "<BBB/>", "<BBB/>", "<BBB/>");
add(data, 3, "/AAA/CCC/DDD/*", "<BBB/>", "<BBB/>", "<EEE/>", "<FFF/>");
add(data, 3, "/*/*/*/BBB", "<BBB/>", "<BBB/>", "<BBB/>", "<BBB/>", "<BBB><BBB/></BBB>");
//according to Galax the document order is :
add(data, 3, "//*",
"<AAA><XXX><DDD><BBB/><BBB/><EEE/><FFF/></DDD></XXX><CCC><DDD><BBB/><BBB/><EEE/><FFF/></DDD></CCC><CCC><BBB><BBB><BBB/></BBB></BBB></CCC></AAA>",
"<XXX><DDD><BBB/><BBB/><EEE/><FFF/></DDD></XXX>", "<DDD><BBB/><BBB/><EEE/><FFF/></DDD>", "<BBB/>", "<BBB/>",
"<EEE/>", "<FFF/>", "<CCC><DDD><BBB/><BBB/><EEE/><FFF/></DDD></CCC>", "<DDD><BBB/><BBB/><EEE/><FFF/></DDD>",
"<BBB/>", "<BBB/>", "<EEE/>", "<FFF/>", "<CCC><BBB><BBB><BBB/></BBB></BBB></CCC>",
"<BBB><BBB><BBB/></BBB></BBB>", "<BBB><BBB/></BBB>", "<BBB/>");
add(data, 4, "/AAA/BBB[1]", "<BBB/>");
add(data, 4, "/AAA/BBB[last()]", "<BBB/>");
add(data, 5, "//@id", "<xml-fragment id=\"b1\"/>", "<xml-fragment id=\"b2\"/>");
add(data, 5, "//BBB[@id]", "<BBB id = \"b1\"/>", "<BBB id = \"b2\"/>");
add(data, 5, "//BBB[@name]", "<BBB name=\"bbb\"/>");
add(data, 5, "//BBB[@*]", "<BBB id = \"b1\"/>", "<BBB id = \"b2\"/>", "<BBB name=\"bbb\"/>");
add(data, 5, "//BBB[not(@*)]", "<BBB/>");
add(data, 6, "//BBB[@id='b1']", "<BBB id = \"b1\"/>");
add(data, 6, "//BBB[@name='bbb']", "<BBB name=\"bbb\"/>");
add(data, 6, "//BBB[normalize-space(@name)='bbb']", "<BBB name=\" bbb \"/>", "<BBB name=\"bbb\"/>");
add(data, 7, "//*[count(BBB)=2]", "<DDD><BBB/><BBB/></DDD>");
add(data, 7, "//*[count(*)=2]", "<DDD><BBB/><BBB/></DDD>", "<EEE><CCC/><DDD/></EEE>");
add(data, 7, "//*[count(*)=3]",
"<AAA><CCC><BBB/><BBB/><BBB/></CCC><DDD><BBB/><BBB/></DDD><EEE><CCC/><DDD/></EEE></AAA>", "<CCC><BBB/><BBB/><BBB/></CCC>");
add(data, 8, "//*[name()='BBB']", "<BBB/>", "<BBB/>", "<BBB/>", "<BBB/>", "<BBB/>");
add(data, 8, "//*[starts-with(name(),'B')]", "<BCC><BBB/><BBB/><BBB/></BCC>",
"<BBB/>", "<BBB/>", "<BBB/>", "<BBB/>", "<BBB/>", "<BEC><CCC/><DBD/></BEC>");
// ykadiysk: Jaxen prints in BF left-to-right order but XPath wants doc order
// add(data, "zvon8.xml", "//*[starts-with(name(),'B')]", "<BCC><BBB/><BBB/><BBB/></BCC>",
// "<BBB/>", "<BBB/>", "<BEC><CCC/><DBD/></BEC>", "<BBB/>", "<BBB/>", "<BBB/>");
add(data, 8, "//*[contains(name(),'C')]", "<BCC><BBB/><BBB/><BBB/></BCC>", "<BEC><CCC/><DBD/></BEC>", "<CCC/>");
add(data, 9, "//*[string-length(name()) = 3]", "<AAA><Q/><SSSS/><BB/><CCC/><DDDDDDDD/><EEEE/></AAA>", "<CCC/>");
add(data, 9, "//*[string-length(name()) < 3]", "<Q/>", "<BB/>");
add(data, 9, "//*[string-length(name()) > 3]", "<SSSS/>", "<DDDDDDDD/>", "<EEEE/>");
add(data, 10, "$this//CCC | $this//BBB", "<BBB/>", "<CCC/>", "<CCC/>");
// Nodes are returned in document order
add(data, 10, "$this/AAA/EEE | $this//BBB", "<BBB/>", "<EEE/>");
add(data, 10, "./AAA/EEE |.//DDD/CCC | ./AAA | .//BBB", "<AAA><BBB/><CCC/><DDD><CCC/></DDD><EEE/></AAA>",
"<BBB/>", "<CCC/>", "<EEE/>");
add(data, 11, "/AAA", "<AAA><BBB/><CCC/></AAA>");
add(data, 11, "/child::AAA", "<AAA><BBB/><CCC/></AAA>");
add(data, 11, "/AAA/BBB", "<BBB/>");
add(data, 11, "/child::AAA/child::BBB", "<BBB/>");
add(data, 11, "/child::AAA/BBB", "<BBB/>");
add(data, 12, "/descendant::*",
"<AAA><BBB><DDD><CCC><DDD/><EEE/></CCC></DDD></BBB><CCC><DDD><EEE><DDD><FFF/></DDD></EEE></DDD></CCC></AAA>",
"<BBB><DDD><CCC><DDD/><EEE/></CCC></DDD></BBB>", "<DDD><CCC><DDD/><EEE/></CCC></DDD>",
"<CCC><DDD/><EEE/></CCC>", "<DDD/>", "<EEE/>", "<CCC><DDD><EEE><DDD><FFF/></DDD></EEE></DDD></CCC>",
"<DDD><EEE><DDD><FFF/></DDD></EEE></DDD>", "<EEE><DDD><FFF/></DDD></EEE>", "<DDD><FFF/></DDD>", "<FFF/>");
add(data, 12, "/AAA/BBB/descendant::*", "<DDD><CCC><DDD/><EEE/></CCC></DDD>",
"<CCC><DDD/><EEE/></CCC>", "<DDD/>", "<EEE/>");
add(data, 12, "//CCC/descendant::*", "<DDD/>", "<EEE/>", "<DDD><EEE><DDD><FFF/></DDD></EEE></DDD>",
"<EEE><DDD><FFF/></DDD></EEE>", "<DDD><FFF/></DDD>", "<FFF/>");
add(data, 12, "//CCC/descendant::DDD", "<DDD/>", "<DDD><EEE><DDD><FFF/></DDD></EEE></DDD>", "<DDD><FFF/></DDD>");
add(data, 13, "//DDD/parent::*", "<BBB><DDD><CCC><DDD/><EEE/></CCC></DDD></BBB>",
"<CCC><DDD/><EEE/></CCC>", "<CCC><DDD><EEE><DDD><FFF/></DDD></EEE></DDD></CCC>", "<EEE><DDD><FFF/></DDD></EEE>");
add(data, 14, "/AAA/BBB/DDD/CCC/EEE/ancestor::*",
"<AAA><BBB><DDD><CCC><DDD/><EEE/></CCC></DDD></BBB><CCC><DDD><EEE><DDD><FFF/></DDD></EEE></DDD></CCC></AAA>",
"<BBB><DDD><CCC><DDD/><EEE/></CCC></DDD></BBB>", "<DDD><CCC><DDD/><EEE/></CCC></DDD>", "<CCC><DDD/><EEE/></CCC>");
add(data, 14, "//FFF/ancestor::*",
"<AAA><BBB><DDD><CCC><DDD/><EEE/></CCC></DDD></BBB><CCC><DDD><EEE><DDD><FFF/></DDD></EEE></DDD></CCC></AAA>",
"<CCC><DDD><EEE><DDD><FFF/></DDD></EEE></DDD></CCC>", "<DDD><EEE><DDD><FFF/></DDD></EEE></DDD>",
"<EEE><DDD><FFF/></DDD></EEE>", "<DDD><FFF/></DDD>");
add(data, 15, "/AAA/BBB/following-sibling::*",
"<XXX><DDD><EEE/><DDD/><CCC/><FFF/><FFF><GGG/></FFF></DDD></XXX>", "<CCC><DDD/></CCC>");
add(data, 15, "//CCC/following-sibling::*", "<DDD/>", "<FFF/>", "<FFF><GGG/></FFF>");
add(data, 16, "/AAA/XXX/preceding-sibling::*", "<BBB><CCC/><DDD/></BBB>");
add(data, 16, "//CCC/preceding-sibling::*", "<BBB><CCC/><DDD/></BBB>",
"<XXX><DDD><EEE/><DDD/><CCC/><FFF/><FFF><GGG/></FFF></DDD></XXX>", "<EEE/>", "<DDD/>");
add(data, 17, "/AAA/XXX/following::*", "<CCC><DDD/></CCC>", "<DDD/>");
add(data, 17, "//ZZZ/following::*", "<FFF><GGG/></FFF>", "<GGG/>",
"<XXX><DDD><EEE/><DDD/><CCC/><FFF/><FFF><GGG/></FFF></DDD></XXX>",
"<DDD><EEE/><DDD/><CCC/><FFF/><FFF><GGG/></FFF></DDD>", "<EEE/>", "<DDD/>", "<CCC/>", "<FFF/>",
"<FFF><GGG/></FFF>", "<GGG/>", "<CCC><DDD/></CCC>", "<DDD/>");
// the preceding axis contains all nodes that are descendants of the root of the tree in which the context
// node is found, are not ancestors of the context node, and occur before the context node in document order
add(data, 18, "/AAA/XXX/preceding::*", "<BBB><CCC/><ZZZ><DDD/></ZZZ></BBB>", "<CCC/>",
"<ZZZ><DDD/></ZZZ>", "<DDD/>");
add(data, 18, "//GGG/preceding::*", "<BBB><CCC/><ZZZ><DDD/></ZZZ></BBB>", "<CCC/>",
"<ZZZ><DDD/></ZZZ>", "<DDD/>", "<EEE/>", "<DDD/>", "<CCC/>", "<FFF/>");
add(data, 19, "/AAA/XXX/descendant-or-self::*", "<XXX><DDD><EEE/><DDD/><CCC/><FFF/><FFF><GGG/></FFF></DDD></XXX>",
"<DDD><EEE/><DDD/><CCC/><FFF/><FFF><GGG/></FFF></DDD>", "<EEE/>", "<DDD/>", "<CCC/>", "<FFF/>", "<FFF><GGG/></FFF>", "<GGG/>");
add(data, 19, "//CCC/descendant-or-self::*", "<CCC/>", "<CCC/>", "<CCC><DDD/></CCC>", "<DDD/>");
add(data, 20, "/AAA/XXX/DDD/EEE/ancestor-or-self::*",
"<AAA><BBB><CCC/><ZZZ><DDD/></ZZZ></BBB><XXX><DDD><EEE/><DDD/><CCC/><FFF/><FFF><GGG/></FFF></DDD></XXX><CCC><DDD/></CCC></AAA>",
"<XXX><DDD><EEE/><DDD/><CCC/><FFF/><FFF><GGG/></FFF></DDD></XXX>",
"<DDD><EEE/><DDD/><CCC/><FFF/><FFF><GGG/></FFF></DDD>", "<EEE/>");
add(data, 20, "//GGG/ancestor-or-self::*",
"<AAA><BBB><CCC/><ZZZ><DDD/></ZZZ></BBB><XXX><DDD><EEE/><DDD/><CCC/><FFF/><FFF><GGG/></FFF></DDD></XXX><CCC><DDD/></CCC></AAA>",
"<XXX><DDD><EEE/><DDD/><CCC/><FFF/><FFF><GGG/></FFF></DDD></XXX>",
"<DDD><EEE/><DDD/><CCC/><FFF/><FFF><GGG/></FFF></DDD>", "<FFF><GGG/></FFF>", "<GGG/>");
add(data, 21, "//GGG/ancestor::*",
"<AAA><BBB><CCC/><ZZZ/></BBB><XXX><DDD><EEE/><FFF><HHH/><GGG><JJJ><QQQ/></JJJ><JJJ/></GGG><HHH/></FFF></DDD></XXX><CCC><DDD/></CCC></AAA>",
"<XXX><DDD><EEE/><FFF><HHH/><GGG><JJJ><QQQ/></JJJ><JJJ/></GGG><HHH/></FFF></DDD></XXX>",
"<DDD><EEE/><FFF><HHH/><GGG><JJJ><QQQ/></JJJ><JJJ/></GGG><HHH/></FFF></DDD>",
"<FFF><HHH/><GGG><JJJ><QQQ/></JJJ><JJJ/></GGG><HHH/></FFF>");
add(data, 21, "//GGG/descendant::*", "<JJJ><QQQ/></JJJ>", "<QQQ/>", "<JJJ/>");
add(data, 21, "//GGG/following::*", "<HHH/>", "<CCC><DDD/></CCC>", "<DDD/>");
add(data, 21, "//GGG/preceding::*", "<BBB><CCC/><ZZZ/></BBB>", "<CCC/>", "<ZZZ/>", "<EEE/>", "<HHH/>");
add(data, 21, "//GGG/self::*", "<GGG><JJJ><QQQ/></JJJ><JJJ/></GGG>");
add(data, 21, "//GGG/ancestor::* | //GGG/descendant::* | //GGG/following::* | //GGG/preceding::* | //GGG/self::*",
"<AAA><BBB><CCC/><ZZZ/></BBB><XXX><DDD><EEE/><FFF><HHH/><GGG><JJJ><QQQ/></JJJ><JJJ/></GGG><HHH/></FFF></DDD></XXX><CCC><DDD/></CCC></AAA>",
"<BBB><CCC/><ZZZ/></BBB>", "<CCC/>", "<ZZZ/>", "<XXX><DDD><EEE/><FFF><HHH/><GGG><JJJ><QQQ/></JJJ><JJJ/></GGG><HHH/></FFF></DDD></XXX>",
"<DDD><EEE/><FFF><HHH/><GGG><JJJ><QQQ/></JJJ><JJJ/></GGG><HHH/></FFF></DDD>", "<EEE/>",
"<FFF><HHH/><GGG><JJJ><QQQ/></JJJ><JJJ/></GGG><HHH/></FFF>", "<HHH/>", "<GGG><JJJ><QQQ/></JJJ><JJJ/></GGG>",
"<JJJ><QQQ/></JJJ>", "<QQQ/>", "<JJJ/>", "<HHH/>", "<CCC><DDD/></CCC>", "<DDD/>");
add(data, 22, "//BBB[position() mod 2 = 0 ]", "<BBB/>", "<BBB/>", "<BBB/>", "<BBB/>");
add(data, 22, "//BBB[ position() = floor(last() div 2 + 0.5) or position() = ceiling(last() div 2 + 0.5) ]",
"<BBB/>", "<BBB/>");
add(data, 22, "//CCC[ position() = floor(last() div 2 + 0.5) or position() = ceiling(last() div 2 + 0.5) ]",
"<CCC/>");
return data;
}
private static void add(List<Object[]> data, int dataset, String xpath, String... expected) {
data.add(new Object[]{dataset, xpath, expected});
}
@Test
public void zvonExample() throws IOException, XmlException {
XmlObject xDoc = XmlObject.Factory.parse(JarUtil.getResourceFromJar("xbean/xmlcursor/xpath/zvon"+dataset+".xml"));
XmlCursor x1 = xDoc.newCursor();
try {
x1.selectPath(xpath);
XmlObject[] exp = new XmlObject[expected.length];
for (int i = 0; i < expected.length; i++) {
exp[i] = XmlObject.Factory.parse(expected[i]);
}
XPathCommon.compare(x1, exp);
} finally {
x1.dispose();
}
}
}