in core/src/main/java/hudson/model/Api.java [92:200]
public void doXml(StaplerRequest req, StaplerResponse rsp,
@QueryParameter String xpath,
@QueryParameter String wrapper,
@QueryParameter String tree,
@QueryParameter int depth) throws IOException, ServletException {
setHeaders(rsp);
String[] excludes = req.getParameterValues("exclude");
if(xpath==null && excludes==null) {
// serve the whole thing
rsp.serveExposedBean(req,bean,Flavor.XML);
return;
}
StringWriter sw = new StringWriter();
// first write to String
Model p = MODEL_BUILDER.get(bean.getClass());
TreePruner pruner = (tree!=null) ? new NamedPathPruner(tree) : new ByDepth(1 - depth);
p.writeTo(bean,pruner,Flavor.XML.createDataWriter(bean,sw));
// apply XPath
FilteredFunctionContext functionContext = new FilteredFunctionContext();
Object result;
try {
Document dom = new SAXReader().read(new StringReader(sw.toString()));
// apply exclusions
if (excludes!=null) {
for (String exclude : excludes) {
XPath xExclude = dom.createXPath(exclude);
xExclude.setFunctionContext(functionContext);
List<org.dom4j.Node> list = (List<org.dom4j.Node>)xExclude.selectNodes(dom);
for (org.dom4j.Node n : list) {
Element parent = n.getParent();
if(parent!=null)
parent.remove(n);
}
}
}
if(xpath==null) {
result = dom;
} else {
XPath comp = dom.createXPath(xpath);
comp.setFunctionContext(functionContext);
List list = comp.selectNodes(dom);
if (wrapper!=null) {
// check if the wrapper is a valid entity name
// First position: letter or underscore
// Other positions: \w (letter, number, underscore), dash or dot
String validNameRE = "^[a-zA-Z_][\\w-\\.]*$";
if(!wrapper.matches(validNameRE)) {
rsp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
rsp.getWriter().print(Messages.Api_WrapperParamInvalid());
return;
}
Element root = DocumentFactory.getInstance().createElement(wrapper);
for (Object o : list) {
if (o instanceof String) {
root.addText(o.toString());
} else {
root.add(((org.dom4j.Node)o).detach());
}
}
result = root;
} else if (list.isEmpty()) {
rsp.setStatus(HttpServletResponse.SC_NOT_FOUND);
rsp.getWriter().print(Messages.Api_NoXPathMatch(xpath));
return;
} else if (list.size() > 1) {
rsp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
rsp.getWriter().print(Messages.Api_MultipleMatch(xpath,list.size()));
return;
} else {
result = list.get(0);
}
}
} catch (DocumentException e) {
LOGGER.log(Level.FINER, "Failed to do XPath/wrapper handling. XML is as follows:"+sw, e);
throw new IOException("Failed to do XPath/wrapper handling. Turn on FINER logging to view XML.",e);
}
if (isSimpleOutput(result) && !permit(req)) {
// simple output prohibited
rsp.sendError(HttpURLConnection.HTTP_FORBIDDEN, "primitive XPath result sets forbidden; implement jenkins.security.SecureRequester");
return;
}
// switch to gzipped output
try (OutputStream o = rsp.getCompressedOutputStream(req)) {
if (isSimpleOutput(result)) {
// simple output allowed
rsp.setContentType("text/plain;charset=UTF-8");
String text = result instanceof CharacterData ? ((CharacterData) result).getText() : result.toString();
o.write(text.getBytes(StandardCharsets.UTF_8));
return;
}
// otherwise XML
rsp.setContentType("application/xml;charset=UTF-8");
new XMLWriter(o).write(result);
}
}