How to generate xpath from xsd?

后端 未结 3 1827
旧巷少年郎
旧巷少年郎 2021-01-12 02:10

How can I generate xpath from an xsd? XSD validates an xml. I am working in a project where I am generating a sample XML from the xsd using java and then generating xpath fr

相关标签:
3条回答
  • 2021-01-12 02:12

    There are a number of problems with such tools:

    The XPath expression generated rarely is a good one. No such tool will produce meaningful predicates beyond position information.

    There is no tool (to my knowledge) that would generate an XPath expression that selects exactly a set of selected nodes.

    Apart from this, such tools used without learning XPath are really harmful -- they support ignorance.

    I would recommend serious learning of XPath using books and other resources such as following.

    https://stackoverflow.com/questions/339930/any-good-xslt-tutorial-book-blog-site-online/341589#341589

    See the following answer for more information..

    Is there an online tester for xPath selectors?

    0 讨论(0)
  • 2021-01-12 02:12

    I've been working on a little library to do just this, though for larger and more complex schemas, there are issues you will need to address on a case-by-case basis (e.g., filters for certain nodes). See https://stackoverflow.com/a/45020739/3096687 for a description of the solution.

    0 讨论(0)
  • 2021-01-12 02:36

    This might be of use:

    import java.io.File;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Stack;
    import javax.xml.parsers.*;
    
    import org.xml.sax.*;
    import org.xml.sax.helpers.DefaultHandler;
    
    /**
     * SAX handler that creates and prints XPath expressions for each element encountered.
     *
     * The algorithm is not infallible, if elements appear on different levels in the hierarchy.
     * Something like the following is an example:
     * - <elemA/>
     * - <elemA/>
     * - <elemB/>
     * - <elemA/>
     * - <elemC>
     * -     <elemB/>
     * - </elemC>
     *
     * will report
     *
     * //elemA[0]
     * //elemA[1]
     * //elemB[0]
     * //elemA[2]
     * //elemC[0]
     * //elemC[0]/elemB[1]       (this is wrong: should be //elemC[0]/elemB[0] )
     *
     * It also ignores namespaces, and thus treats <foo:elemA> the same as <bar:elemA>.
     */
    
    public class SAXCreateXPath extends DefaultHandler {
    
        // map of all encountered tags and their running count
        private Map<String, Integer> tagCount;
        // keep track of the succession of elements
        private Stack<String> tags;
    
        // set to the tag name of the recently closed tag
        String lastClosedTag;
    
        /**
         * Construct the XPath expression
         */
        private String getCurrentXPath() {
            String str = "//";
            boolean first = true;
            for (String tag : tags) {
                if (first)
                    str = str + tag;
                else
                    str = str + "/" + tag;
                str += "["+tagCount.get(tag)+"]";
                first = false;
            }
            return str;
        }
    
        @Override
        public void startDocument() throws SAXException {
            tags = new Stack();
            tagCount = new HashMap<String, Integer>();
        }
    
        @Override
        public void startElement (String namespaceURI, String localName, String qName, Attributes atts)
            throws SAXException
        {
            boolean isRepeatElement = false;
    
            if (tagCount.get(localName) == null) {
                tagCount.put(localName, 0);
            } else {
                tagCount.put(localName, 1 + tagCount.get(localName));
            }
    
            if (lastClosedTag != null) {
                // an element was recently closed ...
                if (lastClosedTag.equals(localName)) {
                    // ... and it's the same as the current one
                    isRepeatElement = true;
                } else {
                    // ... but it's different from the current one, so discard it
                    tags.pop();
                }
            }
    
            // if it's not the same element, add the new element and zero count to list
            if (! isRepeatElement) {
                tags.push(localName);
            }
    
            System.out.println(getCurrentXPath());
            lastClosedTag = null;
        }
    
        @Override
        public void endElement (String uri, String localName, String qName) throws SAXException {
            // if two tags are closed in succession (without an intermediate opening tag),
            // then the information about the deeper nested one is discarded
            if (lastClosedTag != null) {
                tags.pop();
            }
            lastClosedTag = localName;
        }
    
        public static void main (String[] args) throws Exception {
            if (args.length < 1) {
                System.err.println("Usage: SAXCreateXPath <file.xml>");
                System.exit(1);
            }
    
            // Create a JAXP SAXParserFactory and configure it
            SAXParserFactory spf = SAXParserFactory.newInstance();
            spf.setNamespaceAware(true);
            spf.setValidating(false);
    
            // Create a JAXP SAXParser
            SAXParser saxParser = spf.newSAXParser();
    
            // Get the encapsulated SAX XMLReader
            XMLReader xmlReader = saxParser.getXMLReader();
    
            // Set the ContentHandler of the XMLReader
            xmlReader.setContentHandler(new SAXCreateXPath());
    
            String filename = args[0];
            String path = new File(filename).getAbsolutePath();
            if (File.separatorChar != '/') {
                path = path.replace(File.separatorChar, '/');
            }
            if (!path.startsWith("/")) {
                path = "/" + path;
            }
    
            // Tell the XMLReader to parse the XML document
            xmlReader.parse("file:"+path);
        }
    }
    
    0 讨论(0)
提交回复
热议问题