Search into different strings - java

I have the next situation, i have a string like xml, I would like to search into this String to the second car_id (<car_id>12345678</car_id>) and get the value
if not avaible to search the car_type (<car_type id_1="2" id_2="32">55555</car_type>)
i tried the next code see below but is not working fine. is there better way to do/loop the Strings? thanks and thanks to Stackoverflow
Strings:
<car_dealer><car_id>2</car_id></car_dealer><car><car_id>12345678</car_id></car>
<car_dealer><car_id>2</car_id></car_dealer><car><car_type id_1="2" id_2="32">55555</car_type></car>
Code:
String carId = input.substring(input.lastIndexOf("<car_id>")+9, input.lastIndexOf("</car_id>"))
String carType= input.substring(input.indexOf("<car><car_type>")+84, input.indexOf("</car>"))

I would strongly discourage you from parsing those strings using regex or indexOf -trickery. Those are always bound to break at some time.
Should your strings that really, really look like xml actually be xml, you could parse the values using xpath. Something like this:
import java.io.IOException;
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class A {
public static void main(String[] args) throws Exception {
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
String xml1 = "<xml><car_dealer><car_id>2</car_id></car_dealer><car><car_id>12345678</car_id></car></xml>";
String xml2 = "<xml><car_dealer><car_id>2</car_id></car_dealer><car><car_type id_1=\"2\" id_2=\"32\">55555</car_type></car></xml>";
Document doc1 = stringToDom(xml1);
Document doc2 = stringToDom(xml2);
XPathExpression expr1 = xpath.compile("//car/car_id/text()");
String carId = (String) expr1.evaluate(doc1, XPathConstants.STRING);
XPathExpression expr2 = xpath.compile("//car/car_type/text()");
String carType = (String) expr2.evaluate(doc2, XPathConstants.STRING);
System.out.println("***");
System.out.println("carId: " + carId);
System.out.println("carType: " + carType);
System.out.println("***");
/* prints
***
carId: 12345678
carType: 55555
***
*/
}
public static Document stringToDom(String xmlSource) throws SAXException,
ParserConfigurationException, IOException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(new InputSource(new StringReader(xmlSource)));
}
}

You can find the car id by using the pattern matching as below. Hope this will help you.
String xmlString = "<car_id>12345678</car_id>afhkjasd<car_id>123456789</car_id>";
Pattern pattern = Pattern.compile("(<car_id>)([0-9]{0,})(</car_id>)");
Matcher matcher = pattern.matcher(xmlString);
while (matcher.find()) {
System.out.println(matcher.group(2));
}

Index of will do the job:
Original:
<car_dealer><car_id>2</car_id></car_dealer><car><car_id>12345678</car_id></car>
<car_dealer><car_id>2</car_id></car_dealer><car><car_type id_1="2" id_2="32">55555</car_type></car>
Index of Solution:
String car_id = input.substring(input.indexOf("<car><car_id>") + "<car><car_id>".length(), input.indexOf("</car_id></car>"));
Do same for others.
Good luck!

Related

java search specific attribut name in the xml file

I wouldlike to search in my xml file all attribut (name) without use element tag node :
xml :
<test 1><test1/>
<test2> <test2/>
<test 3 id="aaa"> </test3>
<test 5> </test5>
<test 6 id="bbb" name="ijof"> </test6>
JAVA :
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new File(path));
root = document.getDocumentElement();
String attribut = root.getAttribute("name");
System.out.println(attribut); // Expected ijof
Did you execute your code at least once? I dont't think so. Otherwise you would have surely noticed that your XML cannot be parsed.
There are several flaws in your example XML:
No root element.
Wrong end tags: It should be <test1></test1> and not <test1><test1/>.
Element names must not contain whitespace and start and end tag must match. It should be <test5> </test5> and not <test 5> </test5>
Apart of that you can use XPATH to get all elements with a name attribute.
Here is a complete example with the XML as a string but this should be irrelevant:
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.IOException;
import java.io.StringReader;
public class FindNameAttribute {
private static final String XML =
"<root>\n" +
" <test1></test1>\n" +
" <test2> </test2>\n" +
" <test3 id=\"aaa\"> </test3>\n" +
" <test4 name=\"4\"/>\n" +
" <test5> </test5>\n" +
" <test6 id=\"bbb\" name=\"ijof\"> </test6>\n" +
" <test7 id=\"bbb\"><child name=\"childname\"/> </test7>\n" +
"</root>\n";
public static void main(String[] args) {
System.out.println(XML);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = null;
try {
builder = factory.newDocumentBuilder();
StringReader reader = new StringReader(XML);
InputSource source = new InputSource(reader);
Document document = builder.parse(source);
XPath xpath = XPathFactory.newInstance().newXPath();
NodeList nodes = (NodeList) xpath.evaluate("//*[#name]", document, XPathConstants.NODESET);
for(int i = 0; i < nodes.getLength(); i++) {
Element el = (Element) nodes.item(i);
String elementName = el.getTagName();
String nameAttribute = el.getAttribute("name");
System.out.println(String.format("Element name: %s, name attribute: %s", elementName, nameAttribute));
}
} catch (ParserConfigurationException | SAXException | IOException | XPathExpressionException e) {
e.printStackTrace();
}
}
}
This is the output:
<root>
<test1></test1>
<test2> </test2>
<test3 id="aaa"> </test3>
<test4 name="4"/>
<test5> </test5>
<test6 id="bbb" name="ijof"> </test6>
<test7 id="bbb"><child name="childname"/> </test7>
</root>
Element name: test4, name attribute: 4
Element name: test6, name attribute: ijof
Element name: child, name attribute: childname
The relevant XPATH expression is: //*[#name]
//: Looks for every element in the document
*: Placeholder for element name. Each name matches.
*[#name]: The [] denotes the predicate. We only want elements with a name attribute.
#: Means the following name is the name of an attribute. Whithout it would be interpreted as an element name

Trying to parse XML data with Java - Getting error: "The method getNodeType() is undefined for the type NodeList"

I'm just starting out with learning how to process/parse XML data in Java. I'm getting the error, "The method getNodeType() is undefined for the type NodeList" on the line, after my for-loop, that contains:
if (n.getNodeType() == Node.ELEMENT_NODE){
The type of error seems like I forgot to import something, but I believe I got everything. I am using an XML example from microsoft, in the following link:
http://msdn.microsoft.com/en-us/library/ms762271(v=vs.85).aspx
Thanks in advance.
import java.io.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Element;
public class Files {
public static void main (String [] args) throws IOException, ParserConfigurationException{
String address = "/home/leo/workspace/Test/Files/src/file.xml";
File xmlFile = new File(address);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = factory.newDocumentBuilder();
Document doc = dBuilder.parse(xmlFile);
doc.getDocumentElement().normalize();
System.out.println(doc.getDocumentElement().getNodeName());
NodeList n = doc.getElementsByTagName("book id");
for (int temp = 0; temp < n.getLength(); temp++){
System.out.println(n.item(temp));
if (n.getNodeType() == Node.ELEMENT_NODE){
Element e = (Element) n;
System.out.println("author : " + e.getAttribute("author"));
System.out.println("title : " + e.getAttribute("title") );
System.out.println("genre : " + e.getAttribute("genre"));
System.out.println("price : " + e.getAttribute("price"));
System.out.println("publish_date : " + e.getAttribute("publish_date"));
System.out.println("description : " + e.getAttribute("description"));
}
}
}
}
You are calling getNodeType() on a NodeList object (n).
You need to call this function on a Node object. Example :
n.item(temp).getNodeType();

getElementsByTagName searching down all levels of XML nodes

I have this XML file:
<root>
<node1>
<name>A</name>
<node2>
<name>B</name>
<node3>
<name>C</name>
<number>001</number>
</node3>
</node2>
</node1>
</root>
I am parsing the file, to get the name for each node, and the corresponding number if existing.
I use:
String number = eElement.getElementsByTagName("number").item(0).getTextContent();
This should give me something like:
Name | Number
A |
B |
C | 001
But I get:
Name | Number
A | 001
B | 001
C | 001
So, I think the getElementsByTagName("Number") is looking for number node in all the children of a node. I don't want that. Does anybody know a workaround?
I thought of using XPath instead of the above method, but I really want to know if there's an existing way. Thanks
You can use the javax.xml.xpath APIs in the JDK/JRE to have much more control over the XML returned over getElementsByTagName.
import java.io.File;
import javax.xml.parsers.*;
import javax.xml.xpath.*;
import org.w3c.dom.*;
public class Demo {
public static void main(String[] args) throws Exception {
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
Document document = docBuilder.parse(new File("filename.xml"));
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
Element element = (Element) xpath.evaluate("//node3/name", document, XPathConstants.NODE);
}
}
Hope this helps,
import java.io.File;
import java.io.IOException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class XML {
public static void main(String[] args) throws IOException {
File input = new File("D:\\sample.xml");
Document doc = Jsoup.parse(input, "UTF-8");
Elements allElements = doc.select("root");
for(Element value : allElements){
System.out.println(value.text());
}
String node3Num = doc.select("node3").tagName("number").text();
System.out.println(node3Num);
}
}
Output:
A B C 001
C 001
I have used jsoup-1.7.2 jar (you can download from jsoup.org)
Assuming that your eElement variable is always one of the <node1/>, <node2/>, … elements in question, then the following code should work when you replace your own snippet mentioned above:
String number = null;
NodeList childNodes = eElement.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node node = childNodes.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE
&& node.getNodeName().equals("number")) {
number = node.getTextContent();
break;
}
}
The number variable will be null when there is no <number/> child; it will contain the number you need otherwise.

Get XML nodes from certain tree level

I need a method like Document.getElementsByTagName(), but one that searches only tags from a certain level (ie, not nested tags with the same name)
Example file:
<script>
<something>
<findme></findme><!-- DO NOT FIND THIS TAG -->
</something>
<findme></findme><!-- FIND THIS TAG -->
</script>
Document.getElementsByTagName() simply returns all findme tags in the document.
Here is an example with XPath
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
public class TestXPath {
private static final String FILE = "a.xml" ;
private static final String XPATH = "/script/findme";
public static void main(String[] args) {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
docFactory.setNamespaceAware(true);
DocumentBuilder builder;
try {
builder = docFactory.newDocumentBuilder();
Document doc = builder.parse(FILE);
XPathExpression expr = XPathFactory.newInstance().newXPath().compile(XPATH);
Object hits = expr.evaluate(doc, XPathConstants.NODESET ) ;
if ( hits instanceof NodeList ) {
NodeList list = (NodeList) hits ;
for (int i = 0; i < list.getLength(); i++ ) {
System.out.println( list.item(i).getTextContent() );
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
With
<script>
<something>
<findme>1</findme><!-- DO NOT FIND THIS TAG -->
</something>
<findme>Find this</findme><!-- FIND THIS TAG -->
<findme>More of this</findme><!-- FIND THIS TAG AS WELL -->
</script>
It yields
Find this
More of this
If you're using DOM, the only way I can think of would be a recursive function that looks at the children of each element.
Use:
/*/findme
This XPath expression selects all findme elements that are children of the top element of the XML document.
This expression:
//findme[count(ancestor::*) = 5]
selects all findme elements in the XML document that have exactly five ancestor - elements -- that is, they all are at "level 6".

using conditions in XPath expressions

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
If your XPath processor is version 2, you can use if expressions: http://www.w3.org/TR/xpath20/#id-conditionals .
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.
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>
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...
#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);

Categories