package org.jeecg.modules.cas.util; import java.io.StringReader; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.w3c.dom.Document; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import lombok.extern.slf4j.Slf4j; /** * 解析cas,ST验证后的xml * */ @Slf4j public final class XmlUtils { /** * Creates a new namespace-aware DOM document object by parsing the given XML. * * @param xml XML content. * * @return DOM document. */ public static Document newDocument(final String xml) { final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); final Map features = new HashMap(); features.put(XMLConstants.FEATURE_SECURE_PROCESSING, true); features.put("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); for (final Map.Entry entry : features.entrySet()) { try { factory.setFeature(entry.getKey(), entry.getValue()); } catch (ParserConfigurationException e) { log.warn("Failed setting XML feature {}: {}", entry.getKey(), e); } } factory.setNamespaceAware(true); try { return factory.newDocumentBuilder().parse(new InputSource(new StringReader(xml))); } catch (Exception e) { throw new RuntimeException("XML parsing error: " + e); } } /** * Get an instance of an XML reader from the XMLReaderFactory. * * @return the XMLReader. */ public static XMLReader getXmlReader() { try { final XMLReader reader = SAXParserFactory.newInstance().newSAXParser().getXMLReader(); reader.setFeature("http://xml.org/sax/features/namespaces", true); reader.setFeature("http://xml.org/sax/features/namespace-prefixes", false); reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); return reader; } catch (final Exception e) { throw new RuntimeException("Unable to create XMLReader", e); } } /** * Retrieve the text for a group of elements. Each text element is an entry * in a list. *

This method is currently optimized for the use case of two elements in a list. * * @param xmlAsString the xml response * @param element the element to look for * @return the list of text from the elements. */ public static List getTextForElements(final String xmlAsString, final String element) { final List elements = new ArrayList(2); final XMLReader reader = getXmlReader(); final DefaultHandler handler = new DefaultHandler() { private boolean foundElement = false; private StringBuilder buffer = new StringBuilder(); public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException { if (localName.equals(element)) { this.foundElement = true; } } public void endElement(final String uri, final String localName, final String qName) throws SAXException { if (localName.equals(element)) { this.foundElement = false; elements.add(this.buffer.toString()); this.buffer = new StringBuilder(); } } public void characters(char[] ch, int start, int length) throws SAXException { if (this.foundElement) { this.buffer.append(ch, start, length); } } }; reader.setContentHandler(handler); reader.setErrorHandler(handler); try { reader.parse(new InputSource(new StringReader(xmlAsString))); } catch (final Exception e) { log.error(e.getMessage(), e); return null; } return elements; } /** * Retrieve the text for a specific element (when we know there is only * one). * * @param xmlAsString the xml response * @param element the element to look for * @return the text value of the element. */ public static String getTextForElement(final String xmlAsString, final String element) { final XMLReader reader = getXmlReader(); final StringBuilder builder = new StringBuilder(); final DefaultHandler handler = new DefaultHandler() { private boolean foundElement = false; public void startElement(final String uri, final String localName, final String qName, final Attributes attributes) throws SAXException { if (localName.equals(element)) { this.foundElement = true; } } public void endElement(final String uri, final String localName, final String qName) throws SAXException { if (localName.equals(element)) { this.foundElement = false; } } public void characters(char[] ch, int start, int length) throws SAXException { if (this.foundElement) { builder.append(ch, start, length); } } }; reader.setContentHandler(handler); reader.setErrorHandler(handler); try { reader.parse(new InputSource(new StringReader(xmlAsString))); } catch (final Exception e) { log.error(e.getMessage(), e); return null; } return builder.toString(); } public static Map extractCustomAttributes(final String xml) { final SAXParserFactory spf = SAXParserFactory.newInstance(); spf.setNamespaceAware(true); spf.setValidating(false); try { final SAXParser saxParser = spf.newSAXParser(); final XMLReader xmlReader = saxParser.getXMLReader(); final CustomAttributeHandler handler = new CustomAttributeHandler(); xmlReader.setContentHandler(handler); xmlReader.parse(new InputSource(new StringReader(xml))); return handler.getAttributes(); } catch (final Exception e) { log.error(e.getMessage(), e); return Collections.emptyMap(); } } private static class CustomAttributeHandler extends DefaultHandler { private Map attributes; private boolean foundAttributes; private String currentAttribute; private StringBuilder value; @Override public void startDocument() throws SAXException { this.attributes = new HashMap(); } @Override public void startElement(final String namespaceURI, final String localName, final String qName, final Attributes attributes) throws SAXException { if ("attributes".equals(localName)) { this.foundAttributes = true; } else if (this.foundAttributes) { this.value = new StringBuilder(); this.currentAttribute = localName; } } @Override public void characters(final char[] chars, final int start, final int length) throws SAXException { if (this.currentAttribute != null) { value.append(chars, start, length); } } @Override public void endElement(final String namespaceURI, final String localName, final String qName) throws SAXException { if ("attributes".equals(localName)) { this.foundAttributes = false; this.currentAttribute = null; } else if (this.foundAttributes) { final Object o = this.attributes.get(this.currentAttribute); if (o == null) { this.attributes.put(this.currentAttribute, this.value.toString()); } else { final List items; if (o instanceof List) { items = (List) o; } else { items = new LinkedList(); items.add(o); this.attributes.put(this.currentAttribute, items); } items.add(this.value.toString()); } } } public Map getAttributes() { return this.attributes; } } public static void main(String[] args) { String result = "\r\n" + " \r\n" + " admin\r\n" + " \r\n" + " UsernamePasswordCredential\r\n" + " true\r\n" + " 2019-08-01T19:33:21.527+08:00[Asia/Shanghai]\r\n" + " RestAuthenticationHandler\r\n" + " RestAuthenticationHandler\r\n" + " false\r\n" + " \r\n" + " \r\n" + ""; String errorRes = "\r\n" + " 未能够识别出目标 'ST-5-1g-9cNES6KXNRwq-GuRET103sm0-DESKTOP-VKLS8B3'票根\r\n" + ""; String error = XmlUtils.getTextForElement(errorRes, "authenticationFailure"); System.out.println("------"+error); String error2 = XmlUtils.getTextForElement(result, "authenticationFailure"); System.out.println("------"+error2); String principal = XmlUtils.getTextForElement(result, "user"); System.out.println("---principal---"+principal); Map attributes = XmlUtils.extractCustomAttributes(result); System.out.println("---attributes---"+attributes); } }