【问题标题】:Create Xpath from XSD in Java在 Java 中从 XSD 创建 Xpath
【发布时间】:2015-04-28 13:23:11
【问题描述】:

我正在使用 Apache XMLSchema 框架来解析和获取 XSD 的元素。现在我需要将一个 XPath 字符串与这些元素中的每一个关联起来。有人可以就我如何做到这一点给出任何想法。任何现有的算法或框架可以做到这一点?

例子:

<?xml version="1.0" encoding="ISO-8859-1" ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

<xs:simpleType name="stringtype">
  <xs:restriction base="xs:string"/>
</xs:simpleType>

<xs:simpleType name="inttype">
  <xs:restriction base="xs:positiveInteger"/>
</xs:simpleType>

<xs:simpleType name="dectype">
  <xs:restriction base="xs:decimal"/>
</xs:simpleType>

<xs:simpleType name="orderidtype">
  <xs:restriction base="xs:string">
    <xs:pattern value="[0-9]{6}"/>
  </xs:restriction>
</xs:simpleType>

<xs:complexType name="shiptotype">
  <xs:sequence>
    <xs:element name="name" type="stringtype"/>
    <xs:element name="address" type="stringtype"/>
    <xs:element name="city" type="stringtype"/>
    <xs:element name="country" type="stringtype"/>
  </xs:sequence>
</xs:complexType>

<xs:complexType name="itemtype">
  <xs:sequence>
    <xs:element name="title" type="stringtype"/>
    <xs:element name="note" type="stringtype" minOccurs="0"/>
    <xs:element name="quantity" type="inttype"/>
    <xs:element name="price" type="dectype"/>
  </xs:sequence>
</xs:complexType>

<xs:complexType name="shipordertype">
  <xs:sequence>
    <xs:element name="orderperson" type="stringtype"/>
    <xs:element name="shipto" type="shiptotype"/>
    <xs:element name="item" maxOccurs="unbounded" type="itemtype"/>
  </xs:sequence>
  <xs:attribute name="orderid" type="orderidtype" use="required"/>
</xs:complexType>

<xs:element name="shiporder" type="shipordertype"/>

</xs:schema>

XPath 为

orderperson-> ./orderperson
name-> ./shipto/name

etc

【问题讨论】:

    标签: java xpath xsd


    【解决方案1】:

    如果架构允许递归结构,或者如果它包含通配符,那么这是一个相当棘手的问题,您需要更精确地指定您的需求。对于相对简单的非递归模式,它应该更直接,但您需要提供额外的信息,例如根元素名称。

    【讨论】:

      【解决方案2】:

      对于您想要的,没有开箱即用的解决方案;您必须使用访问者模式编写自己的代码。或者,如果这是您为运行时使用而不是在运行时动态生成的设计时工件,您可以使用类似于SO post 的解决方案。

      【讨论】:

        【解决方案3】:

        我认为这可能会有所帮助:

        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);
            }
        }
        

        致谢:http://www.coderanch.com/how-to/java/SAXCreateXPath

        【讨论】:

          【解决方案4】:

          读到字里行间的一些地方,我正在尝试回答这个问题。您可以查看JXPath,它允许您使用 XPath 表达式来遍历 Java 中的对象图。我有一种预感,这就是你想要达到的目标。不过我可能弄错了:)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-10-05
            • 2010-09-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多