I am trying to parse a POM file using Nokogiri, and want to get the first level child nodes.
My POM file looks something like this:
<project xmlns="some.maven.link">
<parent>
<groupId>parent.jar</groupId>
<artifactId>parent-jar</artifactId>
</parent>
<groupId>child.jar</groupId>
<artifactId>child-jar</artifactId>
</project>
I am trying to fetch the artifactId "child-jar" but the XPath that I am using is possibly incorrect and it's fetching me "parent.jar" as the first occurence.
This is my Ruby code:
#pom = Nokogiri::XML(File.open(file_path))
p #pom.xpath("/project/artifactId", project"=>"http://maven.apache.org/POM/4.0.0")[0].text
I can access the second element but that just would be a hack.
Your XML sample does not appear to be correct. Simplifying it:
require 'nokogiri'
doc = Nokogiri::XML(<<EOT)
<project>
<parent>
<groupId>parent.jar</groupId>
<artifactId>parent-jar</artifactId>
</parent>
<groupId>child.jar</groupId>
<artifactId>child-jar</artifactId>
</project>
EOT
doc.at('project > artifactId').text # => "child-jar"
Using XPath I'd use:
doc.at('/project/artifactId').text # => "child-jar"
I'd suggest learning the difference between search, xpath, css and their at* cousins which are all documented in the "Searching a XML/HTML Document" and Node documentation.
In the above example I removed the XML namespace information to simplify things. XML namespaces are useful, but also are irritating and in your example XML you'd broken it by not supplying a valid URL. Fixing the example with:
<project xmlns="http://www.w3.org/1999/xhtml">
I can use:
namespaces = doc.collect_namespaces # => {"xmlns"=>"http://www.w3.org/1999/xhtml"}
doc.at('project > artifactId', namespaces).text # => "child-jar"
or:
doc.at('xmlns|project > xmlns|artifactId').text # => "child-jar"
I prefer and recommend the first because it's more readable and less noisy.
Nokogiri's implementation of CSS in selectors helps simplify most selectors. Passing in the collected namespaces in the document simplifies searches, whether you're using CSS or XPath.
These also work:
doc.at('/xmlns:project/xmlns:artifactId').text # => "child-jar"
doc.at('/foo:project/foo:artifactId', {'foo' => "http://www.w3.org/1999/xhtml"}).text # => "child-jar"
Note that the second uses a renamed namespace, which is useful if you're dealing with redundant xmlns declarations in the document and need to differentiate between them.
Nokogiri's "Namespaces" tutorial is helpful.
Related
There are lots of great Ruby libraries out there to generate XML documents, but I can't find any which support the generation of XML attributes with periods in their names.
The end goal here is to build a Ruby lib which auto generates Jenkins templates.
Here is an example Jenkins job field parameter, which as you can see, uses attributes with periods in the name:
<properties>
<hudson.model.ParametersDefinitionProperty>
<parameterDefinitions>
<hudson.model.StringParameterDefinition>
<name>MESSAGE</name>
<description/>
<defaultValue>Hello world!</defaultValue>
</hudson.model.StringParameterDefinition>
</parameterDefinitions>
</hudson.model.ParametersDefinitionProperty>
</properties>
Does anyone know how I could do this? Any way to bend the libraries which already exist to support this?
The solution is to use dynamic dispatching:
builder = Nokogiri::XML::Builder.new do |xml|
xml.properties {
xml.send('foo.bar', 'zaa')
}
end
<?xml version="1.0"?>
<properties>
<foo.bar>zaa</foo.bar>
</properties>
I am using Maven Versions plugin's update-properties goal to update properties in pom.xml of multiples projects. (https://www.mojohaus.org/versions-maven-plugin/update-properties-mojo.html). I want the latest version of the dependency for properties.
Now, there are some binaries with wrong versions. I want my code to ignore these versions. For this, I have created my "rules.xml" file. I want to provide it as -DrulesUri argument to update-properties goal.
I already tried specifying this rules.xml file in pom.xml file of project as shown on (Maven versions plugin: reference a rule.xml from a maven dependency?). This worked as the plugin could successfully ignore specified versions in rules.xml. So, there is no problem with rules.xml file. But, this is not useful in my case, since there are many projects involved and I cannot update pom.xml of each project.
The documentation of rulesUri property says "URI of a ruleSet file containing the rules that control how to compare version numbers. The URI could be either a Wagon URI or a classpath URI (e.g. classpath:///package/sub/package/rules.xml)." This much documentation is not helping me. I would want an example on how to specify the rules.xml file in -DrulesUri argument. I tried specifying the rules.xml file as local relative path / absolute path. But, update-properties goal does not seem to recognize the rules and just proceeds similar to execution without -DrulesUri argument. I tried reading https://maven.apache.org/wagon/ to understand Wagon URIs. But, I did not find a simple way to upload my rules.xml somewhere and then use this Wagon URI to specify in -DrulesUri.
This is my rules.xml file :-
<?xml version="1.0" encoding="UTF-8"?>
<ruleset xmlns="http://mojo.codehaus.org/versions-maven-plugin/rule/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" comparisonMethod="maven" xsi:schemaLocation="http://mojo.codehaus.org/versions-maven-plugin/rule/2.0.0 http://mojo.codehaus.org/versions-maven-plugin/xsd/rule-2.0.0.xsd">
<ignoreVersions>
<ignoreVersion type="regex">25243.*.*</ignoreVersion>
</ignoreVersions>
<rules>
</rules>
</ruleset>
Use -Dmaven.version.rules
Example:
mvn versions:display-dependency-updates -Dmaven.version.rules=file:///$HOME/.m2/rules.xml
From AbstractVersionsReport.java source code:
/**
* URI of a ruleSet file containing the rules that control how to compare
* version numbers. The URI could be either a Wagon URI or a classpath URI
* (e.g. <code>classpath:///package/sub/package/rules.xml</code>).
*
* #since 1.0-alpha-3
*/
#Parameter( property = "maven.version.rules" )
private String rulesUri;
I’m trying to add dependency to maven pom.xml file using approach described in this post…
def model = readMavenPom file: 'pom.xml'
dep = [
groupId : "org.foo",
artifactId : "bar"
]
model.addDependency(model.&addDependency.parameterTypes[0].newInstance(dep))
…but I’m facing an error which sounds like:
Groovy.lang.MissingMethodException: No signature of method: java.lang.Class.newInstance() is applicable for argument types: (java.util.LinkedHashMap) values: [[groupId:org.foo, artifactId:bar]]
Possible solutions: newInstance(), newInstance(), newInstance([Ljava.lang.Object;), isInstance(java.lang.Object)
What am I doing wrong? I spent 7 days for now trying to fix this thing and add dependency to pom file, but no luck. The only emergency exit here is to replace file contents using shell script, but it’s the least wanted solution. Yes, I can also parse xml file using groovy methods, but it’s not what we wanted, too.
I am trying to template various XML files. What I want to do is be able to build out a Parent XML by including several Child XML files. This should happen during the expand()->copy() using the SimpleTemplateEngine
as an example:
Gradle:
processResources {
exclude '**/somedir/*'
propList.DESCRIPTION = 'a description goes here'
expand(propList)
}
Parent.XML:
<xml>
<line1>something</line1>
<%include file="Child.XML" %>
</xml>
The documentation states that the SimpleTemplateEngine uses JSP <% syntax and <%= expressions, but does not necessarily provide a list of supported functions.
include fails with it not being a valid method on the resulting SimpleTemplateScript, maybe I meant eval?
The closest I've come to getting something to work is:
<xml>
<line1>something</line1>
<% evaluate(new File("Child.xml")) %>
</xml>
That results in 404 of the Child.xml as it's looking at the process working directory, rather than that of the Parent file. If I reference it as "build/resources/main/templates..../Child.xml", then I get 'unexpected token: < # line....' errors from parsing the Child.
Can this be done? Do I need to change template engines, if that's even possible? Ideally it should process any tokens in Child as well.
This is all very simple in JSP. I somehow got the impression I can treat these files like they're GSP, but I'm not sure how to properly use the GSP tags, if that's even true.
Any help, as always, is greatly appreciated.
Thank you.
This documentation doesn't mention JSP. The syntax for the SimpleTemplateEngine is ${}.
Using Gradle 3.4-rc2, if I have this build.gradle file:
task go(type: ProcessResources) {
from('in') {
include 'root.xml'
}
into 'out'
def props = [:]
props."DESCRIPTION" = "description"
expand(props)
}
where in/root.xml is:
<doc>
<name>root</name>
<desc>${DESCRIPTION}</desc>
${new File("in/childA.xml").getText()}
</doc>
and in/childA.xml is:
<child>
<name>A</name>
</child>
then the output is:
<doc>
<name>root</name>
<desc>description</desc>
<child>
<name>A</name>
</child>
</doc>
I have seen two different syntax in Karaf to add a repo, e.g.,
features:addurl mvn:org.apache.camel/camel-example-osgi/2.10.0/
xml/features
features:addurl mvn:org.apache.camel/camel-example-osgi/2.10.0/
xml
Can someone explain the difference between the 2? I believe they are both referring to a features file but they are in different locations?
features:addurl mvn:org.apache.camel/camel-example-osgi/2.10.0/xml
Doesn't actually work for me. BUT I think can break down what is happening.
mvn:org.apache.camel/camel-example-osgi/2.10.0 is a maven URl with an implicit 'type' and 'classifier'. The type is 'jar' and the classifier is empty, by default. Therefore it resolves to a file called camel-example-osgi-2.10.0.jar. (artifactId-version[-classifier].type)
In this case:
mvn:org.apache.camel/camel-example-osgi/2.10.0/xml is a type of 'xml' and no classifier. This resolves to a file called camel-example-osgi-2.10.0.xml, which doesn't exist.
mvn:org.apache.camel/camel-example-osgi/2.10.0/xml/features is a type of 'xml' and a classifier of 'features'. This, then, resolves to a file called camel-example-osgi-2.10.0-features.xml . We can look on the server and see that this file exists: http://repo1.maven.org/maven2/org/apache/camel/camel-example-osgi/2.10.0/
I can't find good documentation for it but 'classifier' adds the -$classifier to the filename. This is how some maven artifacts have a classifier of -jdkN and -jdkM or -jdbc4 or -jdbc3 on them.
References: https://ops4j1.jira.com/wiki/display/paxurl/Mvn+Protocol
http://maven.apache.org/pom.html#POM_Relationships