Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parse XML file to get all Namespace information

I want to be able to get all namespace information from a given XML File.

So for example, if the input XML File is something like:

<ns1:create xmlns:ns1="http://predic8.com/wsdl/material/ArticleService/1/">
   <ns1:article xmlns:ns1="xmlns:ns1='http://predic8.com/material/1/">
      <ns1:id>1</ns1:id>
      <description>bar</description>
      <name>foo</name>
      <ns1:price>
         <amount>00.00</amount>
         <currency>USD</currency>
      </ns1:price>
      <ns1:price>
         <amount>11.11</amount>
         <currency>AUD</currency>
      </ns1:price>
   </ns1:article>
   <ns1:article xmlns:ns1="xmlns:ns1='http://predic8.com/material/1/">
      <ns1:id>2</ns1:id>
      <description>some name</description>
      <name>some description</name>
      <ns1:price>
         <amount>00.01</amount>
         <currency>USD</currency>
      </ns1:price>
   </ns1:article>
</ns1:create>

I would like to expect an output that looks something like this (in this case comma-separated):

create, ns1, http://predic8.com/wsdl/material/ArticleService/1/
article, ns1, http://predic8.com/material/1/
price, ns1, http://predic8.com/material/1/
id, ns1, http://predic8.com/material/1/

Important notes:

It is important that we also consider sub-nodes which are defined within a specific namespace, but whose definition may be defined at a higher node. For example, we would still like to pick up the node ns1:id, where we need to trace back to the parent node ns1:article to discover that the namespace url is xmlns:ns1='http://predic8.com/material/1/

I am implementing in Java, so I would not mind either a Java-based solution, or even a XSLT-based solution might seem appropriate.

like image 880
Larry Avatar asked Dec 06 '22 13:12

Larry


2 Answers

This can be done with a single XPath 2.0 expression:

distinct-values(//*[name()!=local-name()]/
   concat(local-name(), ', ', substring-before(name(), ':'), ', ', namespace-uri())
like image 50
Michael Kay Avatar answered Dec 09 '22 03:12

Michael Kay


I would use the built-in XMLStreamReader, which is the interface implemented by the streaming XML parser (get to it from the XMLInputFactory class). Its getName method returns a QName, which should give you everything you need.

Something along the lines of:

File file = new File("samples/sample11.xml");
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
XMLStreamReader reader = inputFactory.createXMLStreamReader(new FileInputStream(file));
Set<String> namespaces = new HashSet<String>();
while (reader.hasNext()) {
      int evt = reader.next();
      if (evt == XMLStreamConstants.START_ELEMENT) {
        QName qName = reader.getName();
        if(qName != null){
            if(qName.getPrefix() != null && qName.getPrefix().compareTo("")!=0)
                namespaces.add(String.format("%s, %s, %s",
                    qName.getLocalPart(), qName.getPrefix(), qName.getNamespaceURI()));
        }
      }
}

for(String namespace : namespaces){
    System.out.println(namespace);              
}
like image 24
Alex Avatar answered Dec 09 '22 01:12

Alex