tags:

views:

83

answers:

5

Hi,

I need to parse through an XML document in the database and search for a given expression in it. Then, I must return a String value if the given expression is present in the XML else I need to parse through the next expression and return another String value and so on.

I achieved this by using the following code:

// An xml document is passed as a Node when getEntryType() method is called

 public static class XMLTextFields {
        public static String getEntryType(Node target) throws XPathExpressionException {
          XPathFactory factory = XPathFactory.newInstance();
          XPath xpath = factory.newXpath();
          String entryType = null;
          String [] expression = new String [] {"./libx:package", "./libx:libapp", "./libx:module"};

          String [] type = new String [] {"Package", "Libapp", "Module" };
          for (int i = 0; i < 3; i ++) {
              XPathExpression expr = xpath.compile(expression[i]);
              Object result = expr.evaluate(target, XPathConstants.NODESET);
              NodeList nodes = (NodeList) result;
              if (nodes.getLength() == 0)
                  continue;
              entryType = (type[i]);
          }
          return entryType;
        }
    }

I am wondering if there is a simpler way to do this? Meaning, is there a way to use the "expression" like a function which returns a string if the expression is present in the xml.

I am guessing I should be able to do something like this but am not exactly sure:

String [] Expression = new String [] {"[./libx:package]\"Package\"", ....} 

Meaning, return "Package" if libx:package node exists in the given XML

A: 

If your XPath processor is version 2, you can use if expressions: http://www.w3.org/TR/xpath20/#id-conditionals .

Steven Ourada
A: 

Yes there is, just use an XPath functions in your expression:

Expression exp = xpath.compile("local-name(*[local-name() = 'package'])")
// will return "package" for any matching elements
exp.evaluate(target, XPathConstants.STRING); 

But this will return "package" instead of "Package". Note the capital P

Below is the Test code:

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.util.Map;
import java.util.HashMap;

public class Test {
       private static Map<String, String> mappings = new HashMap<String, String>();
       static {
          mappings.put("package", "Package");
          mappings.put("libapp", "Application");
          mappings.put("module", "Module");
       }

       public static void main(String[] args) throws Throwable {
          XPathFactory factory = XPathFactory.newInstance();
          XPath xpath = factory.newXPath();
          String entryType = null;
          XPathExpression [] expressions = new XPathExpression[] {
             xpath.compile("local-name(*[local-name() = 'package'])"),
             xpath.compile("local-name(*[local-name() = 'libapp'])"),
             xpath.compile("local-name(*[local-name() = 'module'])")
          };

          DocumentBuilderFactory fac = DocumentBuilderFactory.newInstance();
          DocumentBuilder parser = fac.newDocumentBuilder();
          Document doc = parser.parse(args[0]);

          for(int i = 0; i < expressions.length; i++) {
            String found = (String) expressions[i].evaluate(doc.getDocumentElement(),
                          XPathConstants.STRING);
            entryType  = mappings.get(found);
            if(entryType != null && !entryType.trim().isEmpty())   {
               break;
            }
          }

          System.out.println(entryType);

       }
}

Contents of text file:

<?xml version="1.0"?>
<root xmlns:libx="urn:libex">
   <libx:package>mypack</libx:package>
   <libx:libapp>myapp</libx:libapp>
   <libx:module>mymod</libx:module>
</root>
naikus
@Naikus: Thanks! My xml document contains either libx:package, libx:libapp or libx:module(NOT ALL THREE). So, I do a continue when local-name() function returns empty else I break from the loop. Now, the entryType String will have the appropriate String.BUT, the string entryType should be "Package" and not "package". (Note the capital P). This is necessary! Is there a way to do it? Please see my test code in the next comment:
sony
getEntryType(..) { ........String [] expression = new String [] {"local-name(*[local-name() = 'package'])", "local-name(*[local-name() = 'libapp'])", "local-name(*[local-name() = 'module'])"}; for(int i=0; i<expression.length; i++) { XPathExpression expr = xpath.compile(expression[i]); entryType = (String) expr.evaluate(target, XPathConstants.STRING); if (entryType.isEmpty()) continue; break; } return entryType; }I may want to return "This is a Package" not 'package'
sony
Your code seems to be correct, but no need to compile expressions on every call of the method. I've updated the code to return a different string if an element is found. I've kept a mapping of element names to "user firendly names".
naikus
A: 

You can use XSLT here. In XSLT you can check the node name by using

<xsl:value-of select="*[starts-with(name(),'libx:package')]" />

OR you can check using

<xsl:if select="name()='libx:package'" > <!-- Your cusotm elements here... --> </xsl:if>

You can check existence of Element OR Attribute this way to validate specific needs.

hope this helps.

Paarth
A: 

In XPath 1.0

concat(translate(substring(local-name(libx:package|libx:libapp|libx:module),
                           1,
                           1),
                 'plm',
                 'PLM'),
       substring(local-name(libx:package|libx:libapp|libx:module),2))

EDIT: It was dificult to understand the path because there was not provided input sample...

Alejandro
A: 

@ALL: Thanks!

I used:

XPathExpression expr = xpath.compile("concat(substring('Package',0,100*boolean(//libx:package))," + "substring('Libapp',0,100*boolean(//libx:libapp)),substring('Module',0,100*boolean(//libx:module)))"); expr.evaluate(target, XPathConstants.STRING);

sony
I am using XPath processor version 1, so this seems to be the best fit.
sony