I have a problem with Apache Digester 3.2 I hope you can help me with:
The XML I have to parse contains the following lines (and much more):
<CountryName
code = "GFR"
name = "Germany"
IsTerritory = "False"
ProfileURL = "germany.doc"/>
The rules for the digester are given by another XML-file:
<pattern value="CountryName">
<object-create-rule classname="model.CodeNamePair"/>
<set-properties-rule/>
<set-next-rule methodname="addCountry"/>
</pattern>
This should create an Object of CodeNamePair (which contains a String 'code' and a String 'name', just like in the XML above.
The next method 'addCountry' is (hopefully) not relevant for this problem which follows now:
The digester is not able to parse this part. It throws a NoSuchMethodException with message:
"java.lang.NoSuchMethodException: Property IsTerritory can't be set"
Although I don't want to parse the IsTerritory property.
Do you know if (and how) I will be able to ignore this property?
Already now: Thank you very much (I hope my question is not written too complicated)
Try
<set-properties-rule>
<ignore attr-name="IsTerritory" />
</set-properties-rule>
instead of
<set-properties-rule/>
(Not tested)
Related
I am testing a web service, which returns an xml like in the example below
<test xmlns="some url">
<a id="482b6f66-0543-49b2-9a22-d70dc1a87032" href="some url">some text</a>
</test>
I looked through RestAssured documentation but I could not find how to check individual xml properties. I want to test "id" property, returned in the response, but my test fails, telling me that actual vs expected is empty, though I can clearly see that the tag is there and id value is present, if I output xml response as a String.
Here's my test:
expect().body("test.a.id", equalTo(expectedId)).when().post(myRequest);
You were missing a #
should be :
expect().body("test.a.#id", equalTo(expectedId)).when().post(myRequest);
Since your response is XML you can use XPath:
expect().body(hasXPath("/test/a/#id"), equalTo(expectedId)).when().post(myRequest);
# is the way you should address attributes in xpath. Note that this might also help you with a solution using XMLPath. (see the examples here)
Perhaps your usage of namespaces might give some troubles though, you can enable that using:
given().
config(newConfig().xmlConfig(xmlConfig().with().namespaceAware(true))).
expect().
body(hasXPath("/yourns:test/yourns:a/#id"), equalTo(expectedId)).when().post(myRequest);
see also: http://code.google.com/p/rest-assured/wiki/Usage#XPath
The solution turned out to be a bit ugly, but I could not find any relevant examples of this usage, so it's all a guess work. Maybe there's a better way, but here's what I came up with:
Here's the code to find and print my id:
String xml = get(myRequest).asString();
XmlPath xmlPath = new XmlPath(xml).setRoot("test");
String id = xmlPath.get("a.#id");
Assert.assertTrue(id.equals(expectedId));
This worked for me with xml:
<example id="12345">
<someStuff></someStuff>
</example>
I could verify the attribute using:
given().
when().
post("/example/get/").
then().
body(
"example.#id", equalTo("12345")
);
The Subversion XML formatted output is a combination of attribute and elements - particularly within the <path> element - see the sample below:
<?xml version="1.0" encoding="UTF-8"?>
<log>
<logentry
revision="29">
<author>bob</author>
<date>2013-02-14T17:21:42.848605Z</date>
<paths>
<path
action="A"
kind="dir"
copyfrom-path="/trunk"
copyfrom-rev="28">/tags/TAG-0.1</path>
</paths>
<msg>Creating tag TAG-0.1</msg>
</logentry>
</log>
I'm trying to use commons digester to parse this the log content into two different POJO's (LogEntry and Path) using the following:
ArrayList<LogEntry> logEntries = new ArrayList<LogEntry>();
digester.push(logEntries);
digester.addObjectCreate("*/logentry", LogEntry.class);
digester.addSetProperties("*/logentry");
digester.addBeanPropertySetter("*/logentry/author");
digester.addBeanPropertySetter("*/logentry/date");
digester.addBeanPropertySetter("*/logentry/msg");
digester.addSetNext("*/logentry", "add");
digester.addObjectCreate("*/logentry/paths/path", Path.class);
digester.addSetProperties("*/logentry/paths/path");
digester.addBeanPropertySetter("*/logentry/paths/path", "value");
digester.addSetNext("*/logentry/paths/path", "addPath");
(note addPath adds the path object being created onto an ArrayList<Path> within the created LogEntry object)
I can't figure out why the Path class is not being fully populated. Based upon the XML I can understand why the copyfrom-rev and copyfrom-path attributes might not be getting copied (due to the hyphen) into the corresponding copyFromRev attributes.
But I can't see any reason why the kind attribute isn't being set within the Path.
Does anyone have any ideas?
I need to use a digester.addSetProperties() call to get the copyfrom-path and copyfrom-rev attributes populated:
digester.addSetProperties("*/logentry/paths/path", "copyfrom-path", "copyfrompath");
digester.addSetProperties("*/logentry/paths/path", "copyfrom-rev", "copyfromrev");
However for some reason the kind attribute still isn't being populated.
I have an issue trying to compare 2 XML documents in Java, using oracle.xml.differ.XMLDiff. The code is fully implemented and I expected it to be working fine, until I discovered an attribute change is not picked up in some instances. To demonstrate this, I have the following:
Setup:
DOMParser parser = new DOMParser();
parser.setPreserveWhitespace(false);
parser.parse(isCurrent);
XMLDocument currentXmlDoc = parser.getDocument();
parser.parse(isPrior);
XMLDocument priorXmlDoc = parser.getDocument();
XMLDiff xmlDiff = new XMLDiff();
xmlDiff.setDocuments(currentXmlDoc, priorXmlDoc);
In the first case, the attribute change in Strike is picked up fine. I have the following 2 XML files:
XML1
<Periods>
<Period Start="2011-03-28" End="2011-04-17" AverageStart="" AverageEnd="" Notional="6000000.0000" OptionType="Swap" Payment="2011-04-19" Strike="72.0934800" Underlying="ZA" ResetStrike="No" ResetNotional="No" QuotingDate="2011-04-17" Multiplier="1.000000" PlusConstant="0.000000" StopLossPercent="" StopLossLevel=""/>
</Periods>
XML2
<Periods>
<Period Start="2011-03-28" End="2011-04-17" AverageStart="" AverageEnd="" Notional="6000000.0000" OptionType="Swap" Payment="2011-04-19" Strike="0.0000000" Underlying="ZA" ResetStrike="No" ResetNotional="No" QuotingDate="2011-04-17" Multiplier="1.000000" PlusConstant="0.000000" StopLossPercent="" StopLossLevel=""/>
</Periods>
In the second case, the attribute change in Strike is not picked up. I have the following 2 XML files:
XML1
<Periods>
<Period Start="2011-03-28" End="2011-04-30" Payment="2011-05-02" Notional="5220000.000000" Strike="176.201900" StopLossPercent="" StopLossLevel=""/>
</Periods>
XML2
<Periods>
<Period Start="2011-03-28" End="2011-04-30" Payment="2011-05-02" Notional="5220000.000000" Strike="0.000000" StopLossPercent="" StopLossLevel=""/>
</Periods>
Does anyone know if I'm doing something wrong, or is there a bug in the XMLDiff package?
Alternatively, does anyone know a different tool that can be used in the same way, just identifying differences in nodes and attributes between XML files, regardless of the order?
Thanks,
Milena
UPDATE: As it's extremely time-consuming to get new external packages approved for use in our system, in the ideal case I'd like to find a solution to making oracle.xml.differ.XMLDiff work. Obviously if there really is a bug and this can't be bypassed I'll consider other tools.
UPDATE 2: Since nobody seems to know about the XMLDiff bug, I'll try implementing the suggested XMLUnit package, it should do the trick.
In a unit test i'm using org.custommonkey.xmlunit.Diff for comparing xml content. See http://xmlunit.sourceforge.net/api/org/custommonkey/xmlunit/Diff.html
I'm comparing xml strings but you can also compare xml w3c documents. I hope you can convert your XMLDocument to either a String of an org.w3c.dom.Document.
my testcase looks like this:
String actualXML = SomeClass.getElement().asXML();
String expectedXML = IOUtils.toString(this.getClass().getResourceAsStream("/expected.xml"));
org.custommonkey.xmlunit.Diff myDiff = new Diff(StringUtils.deleteWhitespace(expectedXML), StringUtils.deleteWhitespace(actualXML));
assertTrue(MessageFormat.format("XML must be simular: {0}\nActual XML:\n{1}\n", myDiff, actualXML), myDiff.similar());
p.s. I also use the apache commons StringUtils.deleteWhitespace() method, cause i'm not interested in white space differences.
I am trying to retrieve the value of an attribute from an xmel file using XPath and I am not sure where I am going wrong..
This is the XML File
<soapenv:Envelope>
<soapenv:Header>
<common:TestInfo testID="PI1" />
</soapenv:Header>
</soapenv:Envelope>
And this is the code I am using to get the value. Both of these return nothing..
XPathBuilder getTestID = new XPathBuilder("local-name(/*[local-name(.)='Envelope']/*[local-name(.)='Header']/*[local-name(.)='TestInfo'])");
XPathBuilder getTestID2 = new XPathBuilder("Envelope/Header/TestInfo/#testID");
Object doc2 = getTestID.evaluate(context, sourceXML);
Object doc3 = getTestID2.evaluate(context, sourceXML);
How can I retrieve the value of testID?
However you're iterating within the java, your context node is probably not what you think, so remove the "." specifier in your local-name(.) like so:
/*[local-name()='Header']/*[local-name()='TestInfo']/#testID worked fine for me with your XML, although as akaIDIOT says, there isn't an <Envelope> tag to be seen.
The XML file you provided does not contain an <Envelope> element, so an expression that requires it will never match.
Post-edit edit
As can be seen from your XML snippet, the document uses a specific namespace for the elements you're trying to match. An XPath engine is namespace-aware, meaning you'll have to ask it exactly what you need. And, keep in mind that a namespace is defined by its uri, not by its abbreviation (so, /namespace:element doesn't do much unless you let the XPath engine know what the namespace namespace refers to).
Your first XPath has an extra local-name() wrapped around the whole thing:
local-name(/*[local-name(.)='Envelope']/*[local-name(.)='Header']
/*[local-name(.)='TestInfo'])
The result of this XPath will either be the string value "TestInfo" if the TestInfo node is found, or a blank string if it is not.
If your XML is structured like you say it is, then this should work:
/*[local-name()='Envelope']/*[local-name()='Header']/*[local-name()='TestInfo']/#testID
But preferably, you should be working with namespaces properly instead of (ab)using local-name(). I have a post here that shows how to do this in Java.
If you don't care for the namespaces and use an XPath 2.0 compatible engine, use * for it.
//*:Header/*:TestInfo/#testID
will return the desired input.
It will probably be more elegant to register the needed namespaces (not covered here, depends on your XPath engine) and query using these:
//soapenv:Header/common:TestInfo/#testID
I'll point out now, that I'm new to using saxon, and I've tried following the docs and examples in the package, but I'm just not having luck with this problem.
Basically, I'm trying to do some xml processing in java using saxon v8. In order to get something working, I took one of the sample files included in the package and modified to my needs. It works so long as I'm not using namespaces, and that is my question. How can I get around the namespace problem? I don't really care to use it, but it exists in my xml, so I either have to use it or ignore it. Either solution is fine.
Anyway, here is my starter code. It doesn't do anything but take an xpath query try to use it against the hard coded xml doc.
public static void main(String[] args) {
String query = args[0];
File XMLStream=null;
String xmlFileName="doc.xml";
OutputStream destStream=System.out;
XQueryExpression exp=null;
Configuration C=new Configuration();
C.setSchemaValidation(false);
C.setValidation(false);
StaticQueryContext SQC=new StaticQueryContext(C);
DynamicQueryContext DQC=new DynamicQueryContext(C);
QueryProcessor processor = new QueryProcessor(SQC);
Properties props=new Properties();
try{
exp=processor.compileQuery(query);
XMLStream=new File(xmlFileName);
InputSource XMLSource=new InputSource(XMLStream.toURI().toString());
SAXSource SAXs=new SAXSource(XMLSource);
DocumentInfo DI=SQC.buildDocument(SAXs);
DQC.setContextNode(DI);
SequenceIterator iter = exp.iterator(DQC);
while(true){
Item i = iter.next();
if(i != null){
System.out.println(i.getStringValue());
}
else break;
}
}
catch (Exception e){
System.err.println(e.getMessage());
}
}
An example XML file is here...
<?xml version="1.0"?>
<ns1:animal xmlns:ns1="http://my.catservice.org/">
<cat>
<catId>8889</catId>
<fedStatus>true</fedStatus>
</cat>
</ns1:animal>
If I run this with a query including the namespace, I get an error. For example:
/ns1:animal/cat/ gives the error: "Prefix ns1 has not been declared".
If I remove the ns1: from the query, it gives me nothing. If I doctor the xml to remove the "ns1:" prepended to "animal" I can run the query /animal/cat/ with success.
Any help would be greatly appreciated. Thanks.
Error message correctly points out that your xpath expression does not indicate what namespace prefix "ns1" means (binds to). Just because document to operate on happens to use binding for "ns1" does not mean it is what should be used: this because in XML, it's the namespace URI that matters, and prefixes are just convenient shortcuts to the real thing.
So: how do you define the binding? There are 2 generic ways; either provide a context that can resolve the prefix, or embed actual URI within XPath expression.
Regarding the first approach, this email from Saxon author mentions JAXP method XPath.setNamespaceContext(), similarly, Jaxen XPath processor FAQ has some sample code that could help
That's not very convenient, as you have to implement NamespaceContext, but once you have an implementation you'll be set.
So the notation approach... let's see: Top Ten Tips to Using XPath and XPointer shows this example:
to match element declared with namespace like:
xmlns:book="http://my.example.org/namespaces/book"
you use XPath name like:
{http://my.example.org/namespaces/book}section
which hopefully is understood by Saxon (or Jaxen).
Finally, I would recommend upgrading to Saxon9 if possible, if you have any trouble using one of above solutions.
If you want to have something working out of the box, you can check out embedding-xquery-in-java. There's github project, which uses Saxon to evaluate some sample XQuery expressions.
Regards