XPath evaluation issue - xpath

I am using xpath to get the siblings of a plugin by filtering on the artefactID of the maven pom.xml.
below is my xml .Using the Xpath expression //plugin/artifactId[text()="test-maven"] i am able to filter the elements , but i want to get the children siblings of the elements like "configuration" and the children inside it. I tried modifying my Xpath to this way
//plugin/artifactId[text()=\"test-maven\"]/../executions/execution/configuration.It returns all the text inside the elements and i am unable to traverse or get the specific node name and value .
Can anyone help on how i can resolve this issue
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.xxx.test</groupId>
<artifactId>xxx-test</artifactId>
<version>0.0.20-SNAPSHOT</version>
<packaging>apk</packaging>
<name>xxx-test</name>
<properties>
<platform.version>2.3.3</platform.version>
<android.sdk.version>3</android.sdk.version>
</properties>
<dependencies>
<dependency>
<groupId>com.google.android</groupId>
<artifactId>android</artifactId>
<!-- <version>${platform.version}</version> -->
<version>17</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
<artifactId>android-maven-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<androidManifestFile>${project.build.directory}/AndroidManifest.xml</androidManifestFile>
<assetsDirectory>${project.basedir}/assets</assetsDirectory>
<resourceDirectory>${project.basedir}/res</resourceDirectory>
<nativeLibrariesDirectory>${project.basedir}/src/main/native</nativeLibrariesDirectory>
<sdk>
<platform>17</platform>
</sdk>
<undeployBeforeDeploy>true</undeployBeforeDeploy>
</configuration>
<extensions>true</extensions>
</plugin>
<plugin>
<groupId>org.xxxsource</groupId>
<artifactId>test-maven</artifactId>
<version>0.0.1</version>
<executions>
<execution>
<id>Maven plugin</id>
<phase>install</phase>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<fileToUpload>${project.build.directory}/${project.artifactId}-${project.version}.apk</fileToUpload>
<!-- <secretKey>b3b47266-2d07-44d2-a4c4-23a64a2c9ff8</secretKey>
<uploadKey>e707d458-c9ae-4ce5-887f-8c70f97ad801-51334304-d180-4031-917f-a5c58768c7ba</uploadKey> -->
<secretKey>b3b47266-211111111d07-44d2-a41111111c4-23a64a2c9ff8</secretKey>
<uploadKey>e707d458-c9ae-4ce111111111115-887f-8111111111111111c70f97ad801-51334304-d180-4031-917f-a5c58768c7ba</uploadKey>
<releaseNote>TEST</releaseNote>
<grantUsers>
<grantUser>c273ae88-2314-4d85-a7e5-2c2cd40638a8</grantUser>
<grantUser>22a8d3df-7724-4941-8bd4-a735a807bc99</grantUser>
</grantUsers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Here is my code which I am using :-
Document doc = builder.parse(file);
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
XPathExpression expr = xpath.compile(path);
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
final Node node = (Node) nodes.item(i);
System.out.println("Node Name " + node.getNodeName());
// System.out.println("Node " + node.getTextContent());
if (node.hasChildNodes()) {
System.out.println("HAS Child");
NodeList nodes1 = (NodeList) node.getChildNodes();
for (int j = 0; j < nodes1.getLength(); j++) {
final Node node1 = (Node) nodes1.item(j);
System.out.println("Node Child " + node1.getNodeName()
+ " value : =" + node1.getTextContent());
}
}
}
Here is my ouyput:-
Node Name configuration
HAS Child
Node Child #text value : =
Node Child fileToUpload value : =${project.build.directory}/${project.artifactId}-${project.version}.apk
Node Child #text value : =
Node Child #comment value : = b3b47266-2d07-44d2-a4c4-23a64a2c9ff8
e707d458-c9ae-4ce5-887f-8c70f97ad801-51334304-d180-4031-917f-a5c58768c7ba
Node Child #text value : =
Node Child secretKey value : =b3b47266-211111111d07-44d2-a41111111c4-23a64a2c9ff8
Node Child #text value : =
Node Child uploadKey value : =e707d458-c9ae-4ce111111111115-887f-8111111111111111c70f97ad801-51334304-d180-4031-917f-a5c58768c7ba
Node Child #text value : =
Node Child releaseNote value : =WLP_TEST from Maven
Node Child #text value : =
Node Child grantUsers value : =
c273ae88-2314-4d85-a7e5-2c2cd40638a8
22a8d3df-7724-4941-8bd4-a735a807bc99
Node Child #text value : =
I am not sure why the #text node is getting printed and if we cane escape that.

getChildNodes() returns all nodes, including text ones (that much is obvious). Thus you have to filter out text nodes using if (node1.nodeType == 1) (there must be a constant for that 1 value though, consult your language/library manual to find out the name).

Related

ASP.NET Core 6 MVC : read xml read outerxml remove tags

I am writing an ASP.NET Core 6 MVC app, and I have to read an XML with this format:
<?xml version="1.0" encoding="utf-8" ?>
<taglines common-copyright="©2007 ">
<tagline brandID="1" brandName="BCBS" >
<registered registered="®Registered">
</registered>
<copyright copyright="©2007">
</copyright>
<tagline2 tagline2="Data.">
</tagline2>
</tagline>
</taglines>
I need to read the content in tag tagline2
The way I am doing it is
private string ReadXMLAnthemFile()
{
string footer = "";
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(String.Concat(this.Environment.WebRootPath,"/img/TagLines.xml"));
foreach (XmlNode node in xmlDocument.SelectNodes("taglines/tagline/tagline2"))
{
footer = node.OuterXml;
}
return footer;
}
But node.OuterXml returns the entire tag
<tagline2 tagline2="Data."></tagline2>
How can I get only the data inside the tag?
Thanks
You don't need to read the "outer" XML - you need to reach into the XML node you've fetched, and read it's tagline2 attribute - if present.
Try something like this:
foreach (XmlNode node in xmlDocument.SelectNodes("taglines/tagline/tagline2"))
{
if (node.Attributes["#tagline2"] != null)
{
footer = node.Attributes["#tagline2"].Value;
}
}
That should get you the .Value of the tagline2 attribute of the XML node that your XPath expression matches - the value would be Data. in your case here.

How could let MyBatis Generator overwriting the already generated *Mapper.xml?

Like title, when i execute the mybatis-generator, i want to overwriting the already generated *Mapper.xml all, not merge!
but i try many config way, it doesn't implement correct.
and everytime is generator the more once the xml content.
like this:
<resultMap id="BaseResultMap" type="com.test.entity.GoodsEntity"> ...
<resultMap id="BaseResultMap" type="com.test.entity.GoodsEntity"> ...
<resultMap id="BaseResultMap" type="com.test.entity.GoodsEntity"> ...
in the properties, i had add this line:
<mybatis.generator.overwrite>true</mybatis.generator.overwrite>
and in the build > plugin, i add below lines:
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.5</version>
<configuration>
<verbose>true</verbose>
<overwrite>true</overwrite>
<configurationFile>${mybatis.generator.configurationFile}</configurationFile>
</configuration>
<executions>
<execution>
<id>Generate MyBatis Artifacts</id>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.test</groupId>
<artifactId>ob-maven-plugin-mybatis-generator</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</plugin>
in the mybatis-generator.xml, i try overwrite config yet.
all config it doesn't work goo.
How could I modify the configuration?
MyBatis generator will always merge XML files if it finds a match. There is currently no option to turn that off.
You can use plugin <plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin" /> in Mybatis Generator 1.3.7 to overwrite xml.
See http://www.mybatis.org/generator/reference/plugins.html
This plugin will disable the XML merge function for generated mapper XML files. This will cause the generator to respect the overwrite flag for XML files in the same way it does for Java files - if overwrite is true, then an existing file will be overwritten, else a new file will be written with a unique name.
This plugin can be helpful if you disable all comments.
Setting <property name="suppressAllComments" value="true" /> in Mybatis Generator configuration file can cause this problem. Mybatis Generator uses comments flag to decide whether to merge XML.
If you disable all comments, you might find the UnmergeableXmlMappersPlugin useful. It will cause the generator to respect the overwrite flag for XML files.
See http://www.mybatis.org/generator/configreference/commentGenerator.html
I was able to get around this by creating a plugin and adding it to the mybatis-generator-config.xml file. Note, of course, that this solution will cause the Mapper.xml files to always be overwritten regardless of whether or not the -overwrite flag is specified.
mybatis-generator-config.xml:
<generatorConfiguration>
...
<context id="myContextId">
<plugin type="com.mydomain.DeleteExistingSqlMapsPlugin"></plugin>
...
</context>
</generatorConfiguration>
DeleteExistingSqlMapsPlugin.java:
...
public class DeleteExistingSqlMapsPlugin extends PluginAdapter {
#Override
public boolean validate(List<String> warnings) {
return true;
}
#Override
public boolean sqlMapGenerated(GeneratedXmlFile sqlMap,
IntrospectedTable introspectedTable)
{
String sqlMapPath = sqlMap.getTargetProject() + File.separator
+ sqlMap.getTargetPackage().replaceAll("\\.", File.separator)
+ File.separator + sqlMap.getFileName();
File sqlMapFile = new File(sqlMapPath);
sqlMapFile.delete();
return true;
}
}
This works because sqlMapGenerated() is called after a Mapper.xml file is created in memory but before it is written to disk.
I encountered the same problem today.To solve this problem, just need to change the version of mybatis-generator-maven-plugin。
<mybatis-generator-maven-plugin.version>1.3.4-SNAPSHOT</mybatis-generator-maven-plugin.version>
I write a plugin to merge xml mapper file.
And modifiy mybatis-generator-core to combine java and xml.
This can keep your xml and java file 's modification not override.
https://github.com/zwxbest/mybatis-generator-plugin
Usage:
<generatorConfiguration>
...
<context id="myContextId">
<plugin type="com.mydomain.CombineXmlPlugin"></plugin>
...
</context>
</generatorConfiguration>
Plugin Code:
package com.haitian.plugins;
import org.mybatis.generator.api.GeneratedXmlFile;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.ShellCallback;
import org.mybatis.generator.api.dom.xml.Element;
import org.mybatis.generator.internal.DefaultShellCallback;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.File;
import java.io.FileInputStream;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* User:zhangweixiao
* Description:
* old nodes is your existing xml file's first level nodes,like <insert><resultMap>
* new nodes is mybatis-generator generate for you to combine
* This compare the first level node's name and "id" attribute of new nodes and old nodes
* if the two equal,then new node will not generate
* so this can make you modification in old nodes not override.
* if you want to regenrate old node,delete it,it will generate new.
*/
public class CombineXmlPlugin extends PluginAdapter {
//shellCallback use TargetProject and TargetPackage to get targetFile
ShellCallback shellCallback = new DefaultShellCallback(false);
//save new nodes
org.mybatis.generator.api.dom.xml.Document document;
#Override
public boolean validate(List<String> warnings) {
return true;
}
/**
* assing document variable to get new nodes
* #param document
* #param introspectedTable
* #return
*/
#Override
public boolean sqlMapDocumentGenerated(org.mybatis.generator.api.dom.xml.Document document,
IntrospectedTable introspectedTable) {
this.document = document;
return true;
}
//new nodes is generated,but not write on disk,we just need to filter.
#Override
public boolean sqlMapGenerated(GeneratedXmlFile sqlMap,
IntrospectedTable introspectedTable) {
try {
//get old nodes
File directory = shellCallback.getDirectory(sqlMap.getTargetProject(), sqlMap.getTargetPackage());
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating(false);
DocumentBuilder db = dbf.newDocumentBuilder();
File xmlFile = new File(directory, sqlMap.getFileName());
if (directory.exists() == false || xmlFile.exists() == false)
return true;
Document doc = db.parse(new FileInputStream(xmlFile));
org.w3c.dom.Element rootElement = doc.getDocumentElement();
NodeList list = rootElement.getChildNodes();
//get new nodes
List<Element> elements = document.getRootElement().getElements();
//get nodeName and the value of id attribute use regex
Pattern p = Pattern.compile("<(\\w+)\\s+id=\"(\\w+)\"");
boolean findSameNode = false;
// traverse new nodes to compare old nodes to filter
for (Iterator<Element> elementIt = elements.iterator(); elementIt.hasNext(); ) {
findSameNode = false;
String newNodeName = "";
String NewIdValue = "";
Element element = elementIt.next();
Matcher m = p.matcher(element.getFormattedContent(0));
if (m.find()) {
//get nodeName and the value of id attribute
newNodeName = m.group(1);
NewIdValue = m.group(2);
}
//if the nodeName of newNode and oldNode are equal
//and the id attribute of newNode and oldNode are equal
//then filter newNode
for (int i = 0; i < list.getLength(); i++) {
Node node = list.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
if (newNodeName.equals(node.getNodeName())) {
NamedNodeMap attr = node.getAttributes();
for (int j = 0; j < attr.getLength(); j++) {
Node attrNode = attr.item(j);
if (attrNode.getNodeName().equals("id") && attrNode.getNodeValue().equals(NewIdValue)) {
//filter new node,just delete it ,and it will not generate
elementIt.remove();
findSameNode = true;
break;
}
}
if (findSameNode == true)
break;
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
}
you add "batchInsert",and delte insertSelective,and modify other node.
then regenerate xml mapper file,only insertSelective will be generated,others will not be override.

Update xml elements with specific id in gradle

I want to make the following changes in the xml file
My test.xml
<root>
<display-name>Some Name</display-name>
....
<resource-ref id='change'>
<resource-name>Change this</resource-name>
</resource-ref>
<resource-ref id='modify'>
<resource-name>Change this too</resource-name>
</resource-ref>
</root>
I want to make changes in this xml file to look like this
<root>
<display-name>Final Name</display-name>
....
<resource-ref id='change'>
<resource-name>After Change</resource-name>
</resource-ref>
<resource-ref id='modify'>
<resource-name>After Modify</resource-name>
</resource-ref>
</root>
The first answer in this question nearly answers my question. But I need to make specific changes for elements with specific id as you can see.
This looks very simple. I tried looking answers and failed to find. Any help is appreciated.
And btw my gradle script looks like this
task ("replace")<<{
def xmlSource = file(path/to/test.xml)
def xmlDest = file(path/to/destination)
def xmlParser = new XmlParser()
xmlParser.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false)
def xmlRoot = xmlParser.parse(xmlSource)
xmlRoot.'display-name'[0].value = 'RTM16'
//Looking for something like this
//xmlRoot.'resource-ref'[#id='change'].'resource-name'[0].value = 'After Change'
//xmlRoot.'resource-ref'[#id='modify'].'resource-name'[0].value = 'After Modify'
def nodePrinter = new XmlNodePrinter(new PrintWriter(new FileWriter(xmlDest)))
nodePrinter.preserveWhitespace = true
nodePrinter.print(xmlRoot)
}
After going through the Node (Groovy 2.4.6) I came up with this
task ("replace")<<{
xmlSource = file(path/to/xml source file)
xmlDest = file(path/to/destinationfile)
def parser = new XmlParser()
def xmlRoot = parser.parse(xmlSource)
xmlRoot.each{
if(it.name().equals("resource-ref")&& it.#id.equals("change")){
it.'resource-name'[0].value = 'After Change'
}
else if(it.name().equals("resource-ref")&& it.#id.equals("modify")){
it.'resource-name'[0].value = 'After Modify'
}
}
def b = new XmlNodePrinter(new PrintWriter(new FileWriter(xmlDest)))
b.preserveWhitespace = true
b.print(z)
}
Not sure if its the best way. But it works

Passing dataProvider parameter inside testng method

I have two #DataProviders:
#DataProvider(name = "smallNumbers")
#DataProvider(name = "bigNumbers")
Variables in pom.xml
<systemPropertyVariables>
<dataP>${dataProvider}</dataP>
</systemPropertyVariables>
Accesing parameter:
String sizeNumbers = System.getProperty("dataP");
And my test:
#Test(dataProvider=sizeNumbers)
dataProvider in test method have to be:
a constant expression
Any idea how to pass variable inside #Test(dataProvider= ?
You cant do this. It is only possible to pass dataprovider directly to method.
Why you choose that way to inject data from dataprovider? Show a bit more about your code architecture cause that's look strange.
EDIT:
You can check this way:
#DataProvider(name = "dp")
public static Object[][] dataInject(){
return new Object[][]{
{sizeNumbers}
};
}
And inside "dp" you can also make some validation for ex. "isNull" etc.
Then in test
#Test(dataProvider = "dp", dataProviderClass = Xyz.class)
public void testFirst(String input){
//...
}

Retrieve value from xml using linq

I have this XML data
<Address Location="ABC">
<Add Location="XYZ1" street="street1" />
<Add Location="VZC" street="street1" />
</Address>
I want to find out the value of <add> --> street which is street1
I have tried it as below, not getting the result
var q = from res in xmlDoc.Descendants("Address")
where res.Attribute("Location").Value == "ABC"
&& res.Element("Add").Attribute("Location").Value == "VZC"
select new
{
streetadd= res.Element("Add").Attribute("street").Value,
};
Please someone suggest how to check the condition for child element in this case.
Try this:
var query = from res in xmlDoc.Descendants("Address")
where res.Attribute("Location").Value == "ABC"
from child in res.Elements("Add")
where child.Attribute("Location").Value == "VZC"
select new
{
streetadd = child.Attribute("street").Value
};

Resources