Duplicate keys filtering in Dataweave - filter

I have a requirement to read the 'Pronoun' value from the below XML data.
in this scenario wd:ID is the duplicate key and I need to read <wd:Value> attribute under <wd:Integration_Field_Override_Data> object which has <wd:ID> = 'Pronoun'
<?xml version="1.0" encoding="UTF-8"?>
<wd:Get_Workers_Response xmlns:wd="urn:com.workday/bsvc" wd:version="v33.0">
<wd:Response_Data>
<wd:Worker>
<wd:Worker_Data>
<wd:Worker_ID>1129</wd:Worker_ID>
<wd:User_ID>126</wd:User_ID>
<wd:Integration_Field_Override_Data>
<wd:Field_Reference>
<wd:ID wd:type="WID">916f7f9977422e610e634</wd:ID>
<wd:ID wd:type="Integration_Document_Field_Name" wd:parent_type="Integration_Document_Name" wd:parent_id="INT005 - OVERRIDE SERVICE - WORKER">Position as of Hire</wd:ID>
</wd:Field_Reference>
<wd:Value>0086186</wd:Value>
</wd:Integration_Field_Override_Data>
<wd:Integration_Field_Override_Data>
<wd:Field_Reference>
<wd:ID wd:type="WID">916f7f969d1b57422e610e734</wd:ID>
<wd:ID wd:type="Integration_Document_Field_Name" wd:parent_type="Integration_Document_Name" wd:parent_id="INT005 - OVERRIDE SERVICE - WORKER">Probation Period Outcome</wd:ID>
</wd:Field_Reference>
</wd:Integration_Field_Override_Data>
<wd:Integration_Field_Override_Data>
<wd:Field_Reference>
<wd:ID wd:type="WID">438411e0d12510b6d9a0000</wd:ID>
<wd:ID wd:type="Integration_Document_Field_Name" wd:parent_type="Integration_Document_Name" wd:parent_id="INT005 - OVERRIDE SERVICE - WORKER">Pronoun</wd:ID>
</wd:Field_Reference>
<wd:Value>He/They</wd:Value>
</wd:Integration_Field_Override_Data>
</wd:Worker_Data>
</wd:Worker>
</wd:Response_Data>
</wd:Get_Workers_Response>
I have added a below filtering logic to retrieve 'Pronoun' value however it may impact if they change the order while generating Pronoun ID.
Can you please help me with better approach to perform this action.
var pronounData = (worker.Worker_Data.*wd#Integration_Field_Override_Data filter((item, index) -> item.Field_Reference..*ID[1] == 'Pronoun')) default null
And retrieve pronoun value as
pronoun: pronounData[0].Value
Expected Output --> "He/They"

You can change the condition of the filter to check if the array of IDs contains the desired string.
Example:
%dw 2.0
output application/java
ns wd urn:com.workday/bsvc
---
(payload.wd#Get_Workers_Response.wd#Response_Data.wd#Worker.wd#Worker_Data
.*wd#Integration_Field_Override_Data
filter((item, index) -> item.Field_Reference..*ID contains 'Pronoun'))[0].wd#Value
Note that the default clause is redundant since the expression already returns null if the desired string is not found.

Related

SpecFlow Coded UI: Multiple public constructors with same maximum parameter count issue

I am using Coded UI & SpecFlow. I have used following template and earlier it was working fine from last 6 months.
https://github.com/aqdasiftekhar/SpecFlowCodedUI/
I am facing following issue from last two days when i try to regenerate feature file.
Exception in Feature.CS File:
We could not find a data exchange file at the path BoDi.ObjectContainerException: Multiple public constructors with same maximum parameter count are not supported! TechTalk.SpecFlow.Utils.CodeDomHelper (resolution path: TechTalk.SpecFlow.CodedUI.MsTest.SpecFlowCodedUITestGenerator)
Please open an issue at https://github.com/techtalk/SpecFlow/issues/
Complete output:
BoDi.ObjectContainerException: Multiple public constructors with same maximum parameter count are not supported! TechTalk.SpecFlow.Utils.CodeDomHelper (resolution path: TechTalk.SpecFlow.CodedUI.MsTest.SpecFlowCodedUITestGenerator)
at BoDi.ObjectContainer.CreateObject(Type type, IEnumerable1 resolutionPath, RegistrationKey keyToResolve) at BoDi.ObjectContainer.TypeRegistration.Resolve(ObjectContainer container, RegistrationKey keyToResolve, IEnumerable1 resolutionPath)
at BoDi.ObjectContainer.CreateObjectFor(RegistrationKey keyToResolve, IEnumerable1 resolutionPath) at BoDi.ObjectContainer.Resolve(Type typeToResolve, IEnumerable1 resolutionPath, String name)
at BoDi.ObjectContainer.<>c__DisplayClass6.b__5(ParameterInfo p)
at System.Linq.Enumerable.WhereSelectArrayIterator2.MoveNext() at System.Linq.Buffer1..ctor(IEnumerable1 source) at System.Linq.Enumerable.ToArray[TSource](IEnumerable1 source)
at BoDi.ObjectContainer.ResolveArguments(IEnumerable1 parameters, RegistrationKey keyToResolve, IEnumerable1 resolutionPath)
at BoDi.ObjectContainer.CreateObject(Type type, IEnumerable1 resolutionPath, RegistrationKey keyToResolve) at BoDi.ObjectContainer.TypeRegistration.Resolve(ObjectContainer container, RegistrationKey keyToResolve, IEnumerable1 resolutionPath)
at BoDi.ObjectContainer.CreateObjectFor(RegistrationKey keyToResolve, IEnumerable1 resolutionPath) at BoDi.ObjectContainer.Resolve(Type typeToResolve, IEnumerable1 resolutionPath, String name)
at BoDi.ObjectContainer.Resolve[T](String name)
at TechTalk.SpecFlow.Generator.GeneratorContainerBuilder.CreateContainer(SpecFlowConfigurationHolder configurationHolder, ProjectSettings projectSettings)
at TechTalk.SpecFlow.Generator.TestGeneratorFactory.CreateGenerator(ProjectSettings projectSettings)
at TechTalk.SpecFlow.VisualStudio.CodeBehindGenerator.Actions.GenerateTestFileAction.GenerateTestFile(GenerateTestFileParameters opts)
Command: C:\Users\aqdas\AppData\Local\Microsoft\VisualStudio\15.0_4d3f9930\Extensions\5yaz3tdw.3ra\TechTalk.SpecFlow.VisualStudio.CodeBehindGenerator.exe
Parameters: GenerateTestFile --featurefile C:\Users\aqdas\AppData\Local\Temp\2\tmpF07B.tmp --outputdirectory C:\Users\aqdas\AppData\Local\Temp\2 --projectsettingsfile C:\Users\aqdas\AppData\Local\Temp\2\tmpF07A.tmp
Working Directory: C:\Users\aqdas\ProjectName\ProjectFolder\Project.TestFolder\packages\SpecFlow.2.1.0\tools
My config File is:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section
name="specFlow" type="TechTalk.SpecFlow.Configuration.ConfigurationSectionHandler, TechTalk.SpecFlow"/>
</configSections>
<specFlow>
<unitTestProvider name="MsTest"
generatorProvider="TechTalk.SpecFlow.CodedUI.MsTest.SpecFlowCodedUITestGenerator, TechTalk.SpecFlow.CodedUI.MsTest"
runtimeProvider="TechTalk.SpecFlow.UnitTestProvider.MsTestRuntimeProvider, TechTalk.SpecFlow" />
</specFlow>
</configuration>
Specflow Generator Code:
namespace TechTalk.SpecFlow.CodedUI.MsTest
{
using System.CodeDom;
using TechTalk.SpecFlow.Generator.UnitTestProvider;
using TechTalk.SpecFlow.Utils;
public class SpecFlowCodedUITestGenerator : MsTestGeneratorProvider
{
public SpecFlowCodedUITestGenerator(CodeDomHelper codeDomHelper)
: base(codeDomHelper)
{
}
public override void SetTestClass(TechTalk.SpecFlow.Generator.TestClassGenerationContext generationContext, string featureTitle, string featureDescription)
{
base.SetTestClass(generationContext, featureTitle, featureDescription);
foreach (CodeAttributeDeclaration customAttribute in generationContext.TestClass.CustomAttributes)
{
if (customAttribute.Name == "Microsoft.VisualStudio.TestTools.UnitTesting.TestClassAttribute")
{
generationContext.TestClass.CustomAttributes.Remove(customAttribute);
break;
}
}
generationContext.TestClass.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference("Microsoft.VisualStudio.TestTools.UITesting.CodedUITestAttribute")));
}
}
}
I have posted issue on GitHub Link https://github.com/techtalk/SpecFlow/issues/1262
I am using
Visual Studio 2017 Version 15.6.7
Microsoft .NET Framework 4.6.1
SpecFlow 2017.2.7 Extension
Specflow 2.0.1 NuGet Package
I will be thankful to you if anyone can help me to fix this issue.
Regards.
I just updated my Specflow version from 2.1 to 1.9 and it worked. this means specflow 1.9+ do not support coded ui when it comes with custom generator provide.

Saxon 9.7 and XMLBeans / XPath

I'm trying to use XPath in my Web Application with Saxon 9.7.0-14 EE and xmlbeans-2.6.0 / xmlbeans-xpath-2.6.0
Movement mov = (Movement) XPathUtils.executeQueryNoResultNull(message.getPayload(), "//trx:Movement [#tipo='RESTO']");
with
public static XmlObject executeQueryNoResultNull(XmlObject source, String query) {
XmlObject[] results = source.selectPath(DECLARE_NS + "$this" + query);
if (results.length == 0) {
return null;
} else {
return results[0];
}
}
and I have this error
java.lang.RuntimeException: Trying XBeans path engine... Trying XQRL... Trying XDK... Trying delegated path engine... FAILED on declare namespace trx='http://www.test.com/xxx/xx/trx';$this//trx:Movement[#tipo='RESTO']
at org.apache.xmlbeans.impl.store.Path.getCompiledPath(Path.java:185)
at org.apache.xmlbeans.impl.store.Path.getCompiledPath(Path.java:136)
at org.apache.xmlbeans.impl.store.Cursor._selectPath(Cursor.java:902)
at org.apache.xmlbeans.impl.store.Cursor.selectPath(Cursor.java:2634)
at org.apache.xmlbeans.impl.values.XmlObjectBase.selectPath(XmlObjectBase.java:476)
at org.apache.xmlbeans.impl.values.XmlObjectBase.selectPath(XmlObjectBase.java:460)
Is the problem XMLBeans ? Can I use only Saxon and remove XMLBeans ?
Here my module.xml
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="app-common">
<resources>
<resource-root path="jsr173_1.0_api.jar"/>
<resource-root path="resolver.jar"/>
<resource-root path="xbean_xpath.jar"/>
<resource-root path="saxon9ee.jar"/>
<resource-root path="saxon9-dom.jar"/>
<resource-root path="xmlbeans-2.6.0.jar"/>
With XMLBeans version 3.1.0, the most recent version of SaxonHE that I have used successfully is 9.2.1-5. Anything at version 9.3 and above triggers the error that you have seen, i.e. a failed attempt to find an XPath engine that can cope with a query with predicates. The XMLBeans docs explain why the query works without the predicate:
By default, XMLBeans supports only very simple XPath expressions. To
execute complex expressions — such as those with predicates, function
calls, and the like — you will need xbean_xpath.jar and the Saxon jars
(see below) on your class path.
With XMLBeans 3.x, you don't need to include xbean_xpath.jar (the classes are included in xmlbeans-3.1.0.jar), although the documentation has not yet been updated to reflect this.
I'm no expert on XMLBeans, but I wonder if the problem is that the "XPath" expression in question
declare namespace trx='http://www.test.com/xxx/xx/trx';$this//trx:Movement[#tipo='RESTO']
is not true XPath (because of the 'declare namespace') and therefore doesn't work with a third-party XPath engine?

xjc binding compiler configuration to add xmlns element to the package-info class?

I am using Gradle to generate jaxb classes in my project. Every thing is working fine but while marshalling the jaxb object we are seeing different namespaces prefixes like ns1, ns2 .. randomly in the output xml. But we dont want this and want to specify specific namespace prefixes for each namespace. I checked here and found the link 15772478 saying we have to have package-info class with xmlns element, How can i say to xjc binding compiler to add xmlns element with prifixes and namespaceURI? below is the gradle configuration i have to generate Jaxb classes from schemas.
ant.taskdef(name: 'xjc', classname: 'com.sun.tools.xjc.XJCTask', classpath:configurations.jaxb.asPath)
ant.jaxbTargetDir = jaxbTargetDir
ant.xjc(destdir: '${jaxbTargetDir}', binding: 'xjc-bindings/bindings.jaxb', extension: true) {
//arg(value: '-npa')
arg(value: '-readOnly')
arg(value: file('src/main/webapp/schemas/primary1.xsd'))
arg(value: file('src/main/webapp/schemas/primary2.xsd'))
arg(value: file('xjc-bindings/xjc-a.xsd'))
arg(value: file('xjc-bindings/xjc-b.xsd'))
}
sample package-info.java generated by xjc binding.
#XmlSchema(namespace = "urn:neustar:names:decedm:1.0")
package biz.neustar.dece.xml.jaxb.decedm;
import javax.xml.bind.annotation.XmlSchema;
I am expecting the package-info class like below.
#XmlSchema(namespace = "<someuri>",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED,
xmlns={
#XmlNs(prefix="someprefix" , namespaceURI = "<some uri>")
})
package biz.neustar.dece.xml.jaxb.core;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlSchema;
Can somebody please suggest me what is the configuration need to achieve this?
I don't want to use NamespacePrefixMapper to specify the prefixes.
You need to update you binding file like following. It will use eCH-0007 as prefix.
<?xml version="1.0"?>
<jxb:bindings version="1.0"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:namespace="http://jaxb2-commons.dev.java.net/namespace-prefix"
xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd
http://jaxb2-commons.dev.java.net/namespace-prefix http://java.net/projects/jaxb2-commons/sources/svn/content/namespace-prefix/trunk/src/main/resources/prefix-namespace-schema.xsd">
<jxb:bindings schemaLocation="eCH-0007-3-0.xsd">
<jxb:schemaBindings>
<jxb:package name="ch.ech.ech0007.v3" />
</jxb:schemaBindings>
<jxb:bindings>
<namespace:prefix name="eCH-0007" />
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
You can check complete example on this link Namespace-prefix.

Is it possible to create entirely new schema on every case?

Is there a way to create entirely new schema on every case?
Using #DatabaseTearDown annotation is not the case here because i need to reset
id generators as some of my test expectation rely on them (maybe it's a bad practice)
Update on rearrange my tests:
In one of my expected datasets i have:
<field oid="1" type="enumerated" name="simple enum field"
dict_oid="1" required="0"
level="1"/>
<field_enum_element field_oid="1"></field_enum_element>
<field_enum_element field_oid="1"></field_enum_element>
<field_enum_element field_oid="1"></field_enum_element>
where oid in term table is the generated id. I want to be sure that there are 3 rows were created in field_enum_element table but if i omit generated ids from expected data set as follows:
<field type="enumerated" name="simple enum field"
dict_oid="1" required="0"
level="1"/>
<field_enum_element></field_enum_element>
<field_enum_element></field_enum_element>
<field_enum_element></field_enum_element>
spring-test-db-unit thinks that there are 0 rows in the table
UPDATE:
#Test
#DatabaseSetup(value = "fieldServiceImplTest/testCreateEnumField.xml")
#ExpectedDatabase(value = "fieldServiceImplTest/testCreateEnumField.expected.xml",
assertionMode = DatabaseAssertionMode.NON_STRICT)
#DatabaseTearDown(value = "fieldServiceImplTest/clear.xml", type = DELETE_ALL)
public void testCreateEnumField() {
FieldDTO fieldDTO = new FieldDTO();
fieldDTO.setName("simple enum field");
fieldDTO.setType("enumerated");
fieldDTO.setLevel("term");
fieldDTO.setIsValueRequired(false);
fieldDTO.setDictionaryId(dictionaryService.findByOid(1L).get().returnIdentity());
List<ItemDTO> itemDTOs = Arrays.asList(new ItemDTO(null, "complete"), new ItemDTO(null, "draft"), new ItemDTO(null, "deleted"));
fieldDTO.setItems(new HashSet<>(itemDTOs));
fieldService.createField(fieldDTO);
}
testCreateEnumField.xml
<?xml version="1.0" encoding="UTF-8"?>
<dataset>
<dictionary changed="2014-01-31 18:11:54" oid="1" client_oid="1" descr="descr" name="dictionary"/>
</dataset>
testCreateEnumField.expected.xml
<?xml version="1.0" encoding="UTF-8"?>
<dataset reset_sequences="hibernate_sequence">
<dictionary changed="2014-01-31 18:11:54" oid="1" client_oid="1" descr="descr" name="dictionary"/>
<field client_oid="1" oid="1" type="enumerated" name="simple enum field"
dict_oid="1" required="0"
level="1"></field>
<enum_element oid="11" client_oid="1" value="deleted"></enum_element>
<enum_element oid="12" client_oid="1" value="draft"></enum_element>
<enum_element oid="13" client_oid="1" value="complete"></enum_element>
<field_enum_element field_oid="1"></field_enum_element>
<field_enum_element field_oid="1"></field_enum_element>
<field_enum_element field_oid="1"></field_enum_element>
</dataset>
Ideally i would like to be able to drop sequence between tests and test cases.
Although I don't exactly know what your use case is, it sounds like it's a good fit for trying the new declarative SQL feature in Spring 4.1 RC1. Here is the JIRA issue that describes what this new feature.
Your code would look something like:
#Test
#Sql("fix-sequence.sql")
public void test() {
//whatever
}
You can find the Javadoc of #Sql here.
Inside fix-sequence.sql you would provide the SQL needed for resetting the db for the tests
I was able to manage the problem by doing a little workaround by dropping sequence table in #Before method with simple native sql query: "drop table hibernate_sequence".
Actually, the better solution is just to include <hibernate_sequence next_val="1"/> into test dataset at #DatabaseSetup phase

How to extract XML data using XPath with Selenium Webdriver

I'm using Selenium Webdriver (ver 2.31.2.0) (.Net) and I'm trying to extract an element (XML) which is returning from the `driver.PageSource'.
My Question: How to get the list of items using the below xpath.
I able to play in FF using XPATH addons but the same code does not work in Selenium Webdriver
any help?
Here is my code in Selenium Webdriver:
var driver = new FirefoxDriver();
driver.Navigate().GoToUrl("http://website_name/languages.xml");
string _page_source = driver.PageSource;
ReadOnlyCollection<IWebElement> webElements = _page_source.FindElementsByXPath("//response//results//items/vList");
my xml looks like this:
<response xmlns="http://schemas.datacontract.org/2004/07/myproj.cnn.com">
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<meta>
</meta>
<results i:type="vList">
<name>Language</name>
<queryValue>language</queryValue>
<displayOrder>0</displayOrder>
<items>
<vList>
<name>English</name>
<displayName>English</displayName>
<displayOrder>0</displayOrder>
<items />
</vList>
<vList>
<name>Swedish</name>
<displayName>Swedish</displayName>
<displayOrder>1</displayOrder>
<items />
</vList>
</items>
</results>
</response>
You can use selenium to browse to and obtain the xml, but work with the xml using .net classes.
The driver.PageSource property is a string, and you should use .Net classes directly to parse the xml represented. Also, there is no method FindElementsByXPath() on a string object, unless this is an extension method that you have written.
Read the xml using the driver.PageSource from selenium
var driver = new FirefoxDriver();
driver.Navigate().GoToUrl("http://website_name/languages.xml");
XmlReader reader = XmlReader.Create(driver.PageSource);
Or, read the xml by directly browsing to the url using
XmlReader reader = XmlReader.Create("http://website_name/languages.xml");
And then use below code to parse and read the xml.
Key point to note is how the namespace information is provided to the xpath.
//load xml document
XElement xmlDocumentRoot = XElement.Load(reader);
//also add the namespace infn, chose a prefix for the default namespace
XmlNameTable nameTable = reader.NameTable;
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(nameTable);
namespaceManager.AddNamespace("a", "http://schemas.datacontract.org/2004/07/myproj.cnn.com");
//now query with your xml - remeber to prefix the default namespace
var items = xmlDocumentRoot.XPathSelectElements("//a:results/a:items/a:vList", namespaceManager);
Console.WriteLine("vlist has {0} items.", items.Count());
foreach (var item in items)
{
Console.WriteLine("Display name: {0}", item.XPathSelectElement("a:displayName",namespaceManager).Value);
}
// OR get a list of all display names using linq
var displayNames = items.Select(x => x.XPathSelectElement("a:displayName", namespaceManager).Value).ToList();
You will need the following namespaces for the above to work:
using System;
using System.Linq;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
The XML input you have posted has a namespace declared: xmlns="http://schemas.datacontract.org/2004/07/myproj.cnn.com". See the next line:
<response xmlns="http://schemas.datacontract.org/2004/07/myproj.cnn.com">
Because this namespace has no prefix it is the default namespace for all elements without a prefix. Which means element <response> and element <results> etc all belong to this namespace.
Read next: http://www.w3schools.com/xml/xml_namespaces.asp
So in you code you need to declare the namespace before any XPath evaluation will work. I do not know how to set the namespace in Selenium Webdriver but you can find it I guess.
Once you declared the namespace you need to use this in your XPath. For example in a XSLT you can declare the namespace as follows:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:foo="http://schemas.datacontract.org/2004/07/myproj.cnn.com">
I now declared the namespace with prefix foo. The XPath that can be used to retrieve all vList elements would be:
/foo:response/foo:results/foo:items/foo:vList
To get all displayName elements you can use:
/foo:response/foo:results/foo:items/foo:vList/foo:displayName
If you want the total count of the elements instead of the list of elements, you can wrap count() around it like:
count(/foo:response/foo:results/foo:items/foo:vList)
count(/foo:response/foo:results/foo:items/foo:vList/foo:displayName)
The XPath you used has a lot of // in it. Only use // if it is really necessary, because it will scan the complete file and takes more resources than necessary if you know the path already.

Resources