Groovy : replace one XML node with another - groovy

I'm trying to replace one node containing 3 subnodes with a new node, containing 2 subnodes.
The replaceNode function (http://docs.groovy-lang.org/latest/html/api/groovy/util/slurpersupport/GPathResult.html) only accepts Closure, and not an object like replaceBody does.
However, replaceBody replaces the body of the node, not the actual node.
I made a simplified example, which can be ran in https://groovyconsole.appspot.com/
import groovy.util.slurpersupport.*;
import groovy.xml.XmlUtil;
class swarco_updated_example_replace_node_test_simple {
static void main(def args){
/* Overlapping entries */
String xmlorg3entries = '''
<map>
<value>
<!-- Overlapping registrations -->
<map>
<name>blabla</name>
<fruits>
<map>
<type>pear</type>
<color>green</color>
</map>
<map>
<type>orange</type>
<color>orange</color>
</map>
<map>
<type>cherry</type>
<color>red</color>
</map>
</fruits>
</map>
</value>
</map>
''';
String xmlreplace2entries = '''
<fruits>
<map>
<type>grapes</type>
<color>green</color>
</map>
<map>
<type>apples</type>
<color>green</color>
</map>
</fruits>
''';
printNodeReplace(xmlorg3entries, xmlreplace2entries);
}
static def printNodeReplace(mainNodeAsString, insertNodeAsString){
//https://stackoverflow.com/questions/30352052/inserting-xml-snippet-into-another-xml-document-in-groovy
def bodyNode = new XmlSlurper( false, false, false ).parseText( mainNodeAsString );
def fragmentNode = new XmlSlurper( false, false, false ).parseText( insertNodeAsString );
//fails
//bodyNode.value.map.fruits.replaceNode(fragmentNode);
bodyNode.value.map.fruits.replaceBody(fragmentNode);
println XmlUtil.serialize(bodyNode);
}
}
The result is a duplicated node. What is the proper way to do this? Clear the existing node and use append for each entry?
<?xml version="1.0" encoding="UTF-8"?><map>
<value>
<map>
<name>blabla</name>
<fruits>
<fruits>
<map>
<type>grapes</type>
<color>green</color>
</map>
<map>
<type>apples</type>
<color>green</color>
</map>
</fruits>
</fruits>
</map>
</value>
</map>

use fragmentNode.children() to append children of the fragmentNode
bodyNode.value.map.fruits.replaceBody(fragmentNode.children());

Related

Failed to send update request to backup node

Gridgain version: 6.5.5
Cache mode: replaced
Cache K-V type: [Integer, Integer []]
Node startup mode: CMD ggstart -v -i
Problem description: When I'm start only one node, it can calculate correctly and the result is right, however, when I'm start multiple node with the example, it doesn't work and the exception information as follows.
SampleComputeNumTask.java:
#Override
public Collection<CbJob<Long, Integer[]>> splitJob(Serializable... args) throws CJobExcuteException {
Collection<CbJob<Long, Integer[]>> list = new ArrayList<CbJob<Long, Integer[]>>();
loadCache(args);
GridCache<Integer, Integer[]> cache = grid.cache("share-hqfx");
for (GridCacheEntry<Integer, Integer[]> entry : cache.entrySet()) {
list.add(new CbJob<Long, Integer[]>(entry.getKey(), new MyCall(), entry.getValue()));
}
return list;
}
#Override
public void loadCache(Serializable... args) throws CJobExcuteException {
GridCache<Integer, Integer[]> cache = grid.cache("share-hqfx");
try {
cache.globalClearAll(0);
} catch (GridException e1) {
e1.printStackTrace();
}
int j = 0;
int a = 0;
int len = args == null ? 1000 : (Integer) args[0];
Integer[] arg = new Integer[len];
for (int i = 1; i < 1000000; i++) {
arg[a] = i;
a++;
if (a == 1000 || i == 1000000) {
++j;
try {
cache.putx(j, arg);
} catch (GridException e) {
e.printStackTrace();
}
a = 0;
arg = new Integer[1000];
}
}
}
Exception trace:
[16:02:03,880][ERROR][gridgain-#60%rest-null%][GridDhtAtomicUpdateFuture] Failed to send update request to backup node (did node leave the grid?): 5e1b14d3-eb17-499d-9f0e-0de9a4a00c90
class org.gridgain.grid.GridException: Failed to deploy class for local deployment [clsName=java.lang.Integer, ldr=GridUriDeploymentClassLoader [urls=[file:/F:/gridgain-fabric-ent/tmp/grid/gg.uri.deployment.tmp/41ed7058-4555-47d7-83e2-773436b2d12e/dirzip_SampleComputeTask5391357847454873740.gar/]]]
For more information see:
Troubleshooting: http://bit.ly/GridGain-Troubleshooting
Documentation Center: http://bit.ly/GridGain-Documentation
at org.gridgain.grid.kernal.processors.cache.GridCacheDeploymentManager.registerClass(GridCacheDeploymentManager.java:624)
at org.gridgain.grid.kernal.processors.cache.GridCacheDeploymentManager.registerClass(GridCacheDeploymentManager.java:562)
at org.gridgain.grid.kernal.processors.cache.GridCacheMessage.prepareObject(GridCacheMessage.java:181)
at org.gridgain.grid.kernal.processors.cache.GridCacheMessage.marshalCollection(GridCacheMessage.java:478)
at org.gridgain.grid.kernal.processors.cache.distributed.dht.atomic.GridDhtAtomicUpdateRequest.prepareMarshal(GridDhtAtomicUpdateRequest.java:576)
at org.gridgain.grid.kernal.processors.cache.GridCacheIoManager.onSend(GridCacheIoManager.java:334)
at org.gridgain.grid.kernal.processors.cache.GridCacheIoManager.send(GridCacheIoManager.java:362)
at org.gridgain.grid.kernal.processors.cache.GridCacheIoManager.send(GridCacheIoManager.java:350)
at org.gridgain.grid.kernal.processors.cache.GridCacheIoManager.send(GridCacheIoManager.java:557)
at org.gridgain.grid.kernal.processors.cache.distributed.dht.atomic.GridDhtAtomicUpdateFuture.map(GridDhtAtomicUpdateFuture.java:324)
at org.gridgain.grid.kernal.processors.cache.distributed.dht.atomic.GridDhtAtomicCache.updateAllAsyncInternal0(GridDhtAtomicCache.java:1005)
at org.gridgain.grid.kernal.processors.cache.distributed.dht.atomic.GridDhtAtomicCache.updateAllAsyncInternal(GridDhtAtomicCache.java:854)
at org.gridgain.grid.kernal.processors.cache.distributed.dht.atomic.GridNearAtomicUpdateFuture.mapSingle(GridNearAtomicUpdateFuture.java:740)
at org.gridgain.grid.kernal.processors.cache.distributed.dht.atomic.GridNearAtomicUpdateFuture.map0(GridNearAtomicUpdateFuture.java:581)
at org.gridgain.grid.kernal.processors.cache.distributed.dht.atomic.GridNearAtomicUpdateFuture.mapOnTopology(GridNearAtomicUpdateFuture.java:454)
at org.gridgain.grid.kernal.processors.cache.distributed.dht.atomic.GridNearAtomicUpdateFuture.map(GridNearAtomicUpdateFuture.java:319)
at org.gridgain.grid.kernal.processors.cache.distributed.dht.atomic.GridDhtAtomicCache$13.apply(GridDhtAtomicCache.java:662)
at org.gridgain.grid.kernal.processors.cache.distributed.dht.atomic.GridDhtAtomicCache$13.apply(GridDhtAtomicCache.java:660)
at org.gridgain.grid.kernal.processors.cache.distributed.dht.atomic.GridDhtAtomicCache.asyncOp(GridDhtAtomicCache.java:584)
at org.gridgain.grid.kernal.processors.cache.distributed.dht.atomic.GridDhtAtomicCache.updateAllAsync0(GridDhtAtomicCache.java:660)
at org.gridgain.grid.kernal.processors.cache.distributed.dht.atomic.GridDhtAtomicCache.putxAsync(GridDhtAtomicCache.java:343)
at org.gridgain.grid.kernal.processors.cache.GridCacheAdapter.putxAsync(GridCacheAdapter.java:2284)
at org.gridgain.grid.kernal.processors.cache.distributed.dht.atomic.GridDhtAtomicCache.putx(GridDhtAtomicCache.java:329)
at org.gridgain.grid.kernal.processors.cache.GridCacheProxyImpl.putx(GridCacheProxyImpl.java:705)
at com.topgether.cbgrid.datagrid.SampleComputeNumTask.loadCache(SampleComputeNumTask.java:64)
at com.topgether.cbgrid.datagrid.SampleComputeNumTask.splitJob(SampleComputeNumTask.java:38)
at com.topgether.cbgrid.datagrid.CGridTask.split(CGridTask.java:53)
at com.topgether.cbgrid.datagrid.CGridTask.split(CGridTask.java:1)
at org.gridgain.grid.compute.GridComputeTaskSplitAdapter.map(GridComputeTaskSplitAdapter.java:111)
at org.gridgain.grid.kernal.processors.task.GridTaskWorker$2.call(GridTaskWorker.java:404)
at org.gridgain.grid.kernal.processors.task.GridTaskWorker$2.call(GridTaskWorker.java:402)
at org.gridgain.grid.util.GridUtils.wrapThreadLoader(GridUtils.java:6078)
at org.gridgain.grid.kernal.processors.task.GridTaskWorker.body(GridTaskWorker.java:401)
at org.gridgain.grid.util.worker.GridWorker.run(GridWorker.java:151)
at org.gridgain.grid.kernal.processors.task.GridTaskProcessor.startTask(GridTaskProcessor.java:607)
at org.gridgain.grid.kernal.processors.task.GridTaskProcessor.execute(GridTaskProcessor.java:365)
at org.gridgain.grid.kernal.GridComputeImpl.execute(GridComputeImpl.java:122)
at org.gridgain.grid.kernal.processors.rest.handlers.task.GridTaskCommandHandler.handleAsyncUnsafe(GridTaskCommandHandler.java:191)
at org.gridgain.grid.kernal.processors.rest.handlers.task.GridTaskCommandHandler.handleAsync(GridTaskCommandHandler.java:138)
at org.gridgain.grid.kernal.processors.rest.GridRestProcessor.handleRequest(GridRestProcessor.java:203)
at org.gridgain.grid.kernal.processors.rest.GridRestProcessor.access$100(GridRestProcessor.java:61)
at org.gridgain.grid.kernal.processors.rest.GridRestProcessor$2.body(GridRestProcessor.java:109)
at org.gridgain.grid.util.worker.GridWorker.run(GridWorker.java:151)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:745)
Configuration:
<bean id="grid.cfg" class="org.gridgain.grid.GridConfiguration">
<!-- Cache configurations. -->
<property name="cacheConfiguration">
<list>
<bean class="org.gridgain.grid.cache.GridCacheConfiguration">
<property name="name" value="share-hqfx" />
<property name="cacheMode" value="REPLICATED" />
<property name="queryIndexEnabled" value="true" />
</bean>
</list>
</property>
<property name="restJettyPath" value="#{ systemEnvironment['GRIDGAIN_HOME'] }/config/jetty-config.xml" />
<property name="deploymentSpi">
<bean class="org.gridgain.grid.spi.deployment.uri.GridUriDeploymentSpi">
<property name="temporaryDirectoryPath" value="#{ systemEnvironment['GRIDGAIN_HOME'] }/tmp/grid" />
</bean>
</property>
<property name="discoverySpi">
<bean class="org.gridgain.grid.spi.discovery.tcp.GridTcpDiscoverySpi">
<property name="ipFinder">
<bean class="org.gridgain.grid.spi.discovery.tcp.ipfinder.vm.GridTcpDiscoveryVmIpFinder">
<property name="addresses">
<list>
<!-- In distributed environment, replace with actual host IP address. -->
<value>127.0.0.1:47500..47509</value>
</list>
</property>
</bean>
</property>
</bean>
</property>
<property name="deploymentMode" value="CONTINUOUS" />
</bean>

Telerik grid updates not working in batch editing

I'm using RadGrid in ASPX, .net 4.5. The data comes up and displays in my grid fine, but I cannot update, insert, or delete records. I have followed the sample version as closely as I can:
http://demos.telerik.com/aspnet-ajax/grid/examples/data-editing/batch-editing/defaultcs.aspx
When I try to modify data in the grid, then hit Save, the grid reloads and the data is unchanged. No errors, just no updates.
Originally I had the grid wrapped in ajax panel, but when these problems occurred, I removed it. That made not much difference; though when I was using ajax panel, often times clicking the Save icon did absolutely nothing. Or appeared to do nothing. So with that gone, the page/grid does normal postbacks EXCEPT that none of my event handlers are being called. Page_Load gets called, but nothing else (for example RadGrid1_BatchEditCommand, RadGrid1_ItemUpdated). It seems these should be getting called.
ASPX code:
<telerik:RadScriptManager runat="server" ID="RadScriptManager1" />
<telerik:RadListBox runat="server" ID="SavedChangesList" Width="600px" Height="200px" Visible="false"></telerik:RadListBox>
<telerik:RadGrid ID="RadGrid1" GridLines="None" runat="server" AllowAutomaticDeletes="True"
AllowAutomaticInserts="True" PageSize="10" Skin="Default" OnItemDeleted="RadGrid1_ItemDeleted" OnItemInserted="RadGrid1_ItemInserted"
OnItemUpdated="RadGrid1_ItemUpdated" OnPreRender="RadGrid1_PreRender" AllowAutomaticUpdates="True" AllowPaging="True"
AutoGenerateColumns="False" Width="1000px" OnBatchEditCommand="RadGrid1_BatchEditCommand" DataSourceID="sqlContractMatrix">
<MasterTableView CommandItemDisplay="TopAndBottom" DataKeyNames="ID" DataSourceID="sqlContractMatrix" HorizontalAlign="NotSet" EditMode="Batch" AutoGenerateColumns="False">
<BatchEditingSettings EditType="Cell" />
<SortExpressions>
<telerik:GridSortExpression FieldName="SiteID,ProductID" SortOrder="Descending" />
</SortExpressions>
<Columns>
<telerik:GridTemplateColumn HeaderText="Site" HeaderStyle-Width="150px" UniqueName="SiteID" DataField="SiteID">
<ItemTemplate>
<%# Eval("SiteName") %>
</ItemTemplate>
<EditItemTemplate>
<telerik:RadDropDownList runat="server" ID="ddlSites" AppendDataBoundItems="true" DataValueField="SiteID" DataTextField="SiteName" DataSourceID="sqlSites">
</telerik:RadDropDownList>
</EditItemTemplate>
</telerik:GridTemplateColumn>
<telerik:GridTemplateColumn HeaderText="Product" HeaderStyle-Width="150px" UniqueName="ProductID" DataField="ProductID">
<ItemTemplate>
<%# Eval("ProductName") %>
</ItemTemplate>
<EditItemTemplate>
<telerik:RadDropDownList runat="server" ID="ddlProducts" DropDownWidth="250" DropDownHeight="400" DefaultMessage="Product" AppendDataBoundItems="true" DataValueField="ProductID" DataTextField="ProductName" DataSourceID="sqlProducts">
</telerik:RadDropDownList>
</EditItemTemplate>
</telerik:GridTemplateColumn>
<telerik:GridAttachmentColumn DataSourceID="sqlContractMatrix" MaxFileSize="1048576" HeaderStyle-Width="250px"
EditFormHeaderTextFormat="Upload File:" HeaderText="HTML Template" AttachmentDataField="BinaryData"
AttachmentKeyFields="ID" FileNameTextField="TemplateFileBinary" DataTextField="TemplateFileBinary"
UniqueName="TemplateFileBinary">
</telerik:GridAttachmentColumn>
<%--
<telerik:GridBoundColumn DataField="TemplateFile" HeaderStyle-Width="200px" HeaderText="Template"
SortExpression="TemplateFile" UniqueName="TemplateFile">
</telerik:GridBoundColumn>
--%>
<telerik:GridBoundColumn DataField="PDFName" HeaderStyle-Width="200px" HeaderText="PDF Name"
SortExpression="PDFName" UniqueName="PDFName">
</telerik:GridBoundColumn>
<telerik:GridButtonColumn ConfirmText="Delete this record?" ConfirmDialogType="RadWindow"
ConfirmTitle="Delete" HeaderText="Delete" HeaderStyle-Width="50px" ButtonType="ImageButton"
CommandName="Delete" Text="Delete" UniqueName="DeleteColumn">
</telerik:GridButtonColumn>
</Columns>
</MasterTableView>
</telerik:RadGrid>
<asp:SqlDataSource ID="sqlContractMatrix" runat="server" ConnectionString="<%$ ConnectionStrings:FitTrack %>"
DeleteCommand="DELETE FROM ContractMatrix WHERE ID = #ID"
InsertCommand="INSERT INTO ContractMatrix (SiteID, ProductID, TemplateFile, PDFName, LastModifiedDate, LastModifiedByID) VALUES (#SiteID, #ProductID, #TemplateFile, #PDFName, #LastModifiedDate, #LastModifiedByID)"
UpdateCommand="UPDATE ContractMatrix SET SiteID = #SiteID, ProductID = #ProductID, TemplateFile = #TemplateFile, PDFName = #PDFName, LastModifiedDate = GETDATE(), LastModifiedByID = #LastModifiedByID WHERE ID = #ID">
<DeleteParameters>
<asp:Parameter Name="ID" Type="Int32"></asp:Parameter>
</DeleteParameters>
<InsertParameters>
<asp:Parameter Name="SiteID" Type="Int32"></asp:Parameter>
<asp:Parameter Name="ProductID" Type="Int32"></asp:Parameter>
<asp:Parameter Name="TemplateFile" Type="String"></asp:Parameter>
<asp:Parameter Name="PDFName" Type="String"></asp:Parameter>
</InsertParameters>
<UpdateParameters>
<asp:Parameter Name="SiteID" Type="Int32"></asp:Parameter>
<asp:Parameter Name="ProductID" Type="Int32"></asp:Parameter>
<asp:Parameter Name="TemplateFile" Type="String"></asp:Parameter>
<asp:Parameter Name="PDFName" Type="String"></asp:Parameter>
<asp:Parameter Name="ID" Type="Int32"></asp:Parameter>
</UpdateParameters>
</asp:SqlDataSource>
<!-- SQL data sources for various lookup tables -->
<asp:SqlDataSource ID="sqlSites" runat="server" ConnectionString="<%$ ConnectionStrings:FitTrack %>" ProviderName="System.Data.SqlClient" SelectCommand="SELECT SiteID, SiteName FROM gym.Site ORDER BY SiteID"></asp:SqlDataSource>
<asp:SqlDataSource ID="sqlProducts" runat="server" ConnectionString="<%$ ConnectionStrings:FitTrack %>" ProviderName="System.Data.SqlClient"></asp:SqlDataSource>
C# code:
protected void RadGrid1_BatchEditCommand(object sender, Telerik.Web.UI.GridBatchEditingEventArgs e)
{
SavedChangesList.Visible = true;
}
protected void RadGrid1_ItemUpdated(object source, Telerik.Web.UI.GridUpdatedEventArgs e)
{
GridEditableItem item = (GridEditableItem)e.Item;
string id = item.GetDataKeyValue("ID").ToString();
if (e.Exception != null)
{
e.KeepInEditMode = true;
e.ExceptionHandled = true;
NotifyUser("Record with ID " + id + " cannot be updated. Reason: " + e.Exception.Message);
}
else
{
NotifyUser("Record with ID " + id + " is updated!");
}
}
protected void RadGrid1_ItemInserted(object source, GridInsertedEventArgs e)
{
if (e.Exception != null)
{
e.ExceptionHandled = true;
NotifyUser("Product cannot be inserted. Reason: " + e.Exception.Message);
}
else
{
NotifyUser("New product is inserted!");
}
}
protected void RadGrid1_ItemDeleted(object source, GridDeletedEventArgs e)
{
GridDataItem dataItem = (GridDataItem)e.Item;
string id = dataItem.GetDataKeyValue("ID").ToString();
if (e.Exception != null)
{
e.ExceptionHandled = true;
NotifyUser("Product with ID " + id + " cannot be deleted. Reason: " + e.Exception.Message);
}
else
{
NotifyUser("Product with ID " + id + " is deleted!");
}
}
Please help. Why are the data updates not occurring? Why are none of the telerik events/methods in the codebehind being called? Only Page_Load() is executing, none of the others.
For me this was down to trying to use OnItemUpdated instead of OnUpdateCommand.
The ItemDeleted, ItemUpdated and ItemInserted events of RadGrid only work in combination with a directly bound ADO type DataSource. I'm using my own DAL so these 3 events weren't firing.
So the fix was to hook up the events OnUpdateCommand and OnDeleteCommand instead. The event handler looks something like this.
protected void radGrid_UpdateCommand(object sender, GridCommandEventArgs e)
{
var gridDataItem = ((GridDataItem)e.Item);
var table = gridDataItem.OwnerTableView;
var keyValues = table.DataKeyValues[gridDataItem.ItemIndex];
// Get key value.
var id = keyValues["id"];
// Get other values
var foo = ((TextBox)gridDataItem["foo"].Controls[0]).Text;
var bar = ((TextBox)gridDataItem["bar"].Controls[0]).Text;
myDAL.Update(id, foo, bar);
}

Remove root tags from an XML document before adding the XML to another file

I'm trying to add several chunks of XML code from one file into another. The problem is, some of these chunks have root tags that don't need to be copied into the destination XML file (that's the case if the root tags equal the pre-defined parent tags). Here's the code I'm currently using to insert the snippet (written in Groovy):
if (addCode.nodeName == parentTags) { //meaning the root tags shouldn't be included
for (org.w3c.dom.Node n : addCode.childNodes) {
//parent is a NodeList
parent.item(parent.length - 1).appendChild(document.importNode(n, true))
}
} else {
parent.item(parent.length - 1).appendChild(document.importNode(addCode, true))
}
And to parse the XML:
Document parseWithoutDTD(Reader r, boolean validating = false, boolean namespaceAware = true) {
FactorySupport.createDocumentBuilderFactory().with { f ->
f.namespaceAware = namespaceAware
f.validating = validating
f.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
f.newDocumentBuilder().with { db ->
db.parse(new InputSource(r))
}
}
}
Here's an example XML file where the root tags shouldn't be included:
<catalogue> <!-- shouldn't be included -->
<message key='type_issuedate'>Date Issued</message>
<message key='type_accessioneddate'>Date Accesioned</message>
</catalogue>
You might have noticed the problem: if I leave out the root tags from the XML files to copy into the other XML file, they throw a parsing exception.
EDIT: here's an (shortened) example of the file to insert to:
<catalogue xml:lang="en" xmlns:i18n="http://apache.org/cocoon/i18n/2.1">
...
<message key="column4">Date</message>
<message key="column5">Summary</message>
<message key="column6">Actions</message>
<message key="restore">Restore</message>
<message key="update">Update</message>
<!-- INSERT XML HERE -->
...
</catalogue>
And an example of XML with root tags to be included (and the corresponding file to insert to):
XML to insert
<dependency>
<groupId>grID</groupId>
<artifactId>artID</artifactId>
<version>${version.number}</version>
</dependency>
XML file to insert into
<?xml version="1.0" encoding="UTF-8"?>
<project>
<dependencies>
<dependency>
<groupId>grID1</groupId>
<artifactId>artID1</artifactId>
<type>jar</type>
<classifier>classes</classifier>
</dependency>
<!-- INSERT XML HERE -->
</dependencies>
</project>
Currently, all of this code isn't working as I want it to work. Can someone help me out?
Much appreciated!
I think (if I understand right), you need something like this:
def insert( parent, data ) {
if( parent.name() == data.name() ) {
data.children().each {
parent.append it
}
}
else {
parent.append data
}
}
So, given
def newdoc = '''<dependency>
| <groupId>grID</groupId>
| <artifactId>artID</artifactId>
| <version>${version.number}</version>
|</dependency>'''.stripMargin()
def doc = '''<?xml version="1.0" encoding="UTF-8"?>
|<project>
| <dependencies>
| <dependency>
| <groupId>grID1</groupId>
| <artifactId>artID1</artifactId>
| <type>jar</type>
| <classifier>classes</classifier>
| </dependency>
| </dependencies>
|</project>'''.stripMargin()
def docnode = new XmlParser().parseText( doc )
def newnode = new XmlParser().parseText( newdoc )
// use head() as I want to add to the first dependencies node
insert( docnode.dependencies.head(), newnode )
println groovy.xml.XmlUtil.serialize( docnode )
You get the output:
<?xml version="1.0" encoding="UTF-8"?><project>
<dependencies>
<dependency>
<groupId>grID1</groupId>
<artifactId>artID1</artifactId>
<type>jar</type>
<classifier>classes</classifier>
</dependency>
<dependency>
<groupId>grID</groupId>
<artifactId>artID</artifactId>
<version>${version.number}</version>
</dependency>
</dependencies>
</project>
And given:
def newdoc = '''<catalogue>
| <message key='type_issuedate'>Date Issued</message>
| <message key='type_accessioneddate'>Date Accesioned</message>
|</catalogue>'''.stripMargin()
def doc = '''<catalogue xml:lang="en" xmlns:i18n="http://apache.org/cocoon/i18n/2.1">
| <message key="column4">Date</message>
| <message key="column5">Summary</message>
| <message key="column6">Actions</message>
| <message key="restore">Restore</message>
| <message key="update">Update</message>
|</catalogue>'''.stripMargin()
def docnode = new XmlParser().parseText( doc )
def newnode = new XmlParser().parseText( newdoc )
insert( docnode, newnode )
println groovy.xml.XmlUtil.serialize( docnode )
you get:
<?xml version="1.0" encoding="UTF-8"?><catalogue xml:lang="en" xmlns:xml="http://www.w3.org/XML/1998/namespace">
<message key="column4">Date</message>
<message key="column5">Summary</message>
<message key="column6">Actions</message>
<message key="restore">Restore</message>
<message key="update">Update</message>
<message key="type_issuedate">Date Issued</message>
<message key="type_accessioneddate">Date Accesioned</message>
</catalogue>
Edit
Ok, given the extra info, does this help? Given the same newdoc and doc strings as above, this script seems to do what you want...
import groovy.xml.*
import groovy.xml.dom.*
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
Document parseWithoutDTD(Reader r, boolean validating = false, boolean namespaceAware = true) {
FactorySupport.createDocumentBuilderFactory().with { f ->
f.namespaceAware = namespaceAware
f.validating = validating
f.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
f.newDocumentBuilder().with { db ->
db.parse(new InputSource(r))
}
}
}
def addCode = parseWithoutDTD( new StringReader( newdoc ) ).documentElement
def document = parseWithoutDTD( new StringReader( doc ) )
def parent = document.documentElement
def parentTags = 'catalogue'
use( DOMCategory ) {
if( addCode.nodeName == parentTags ) {
addCode.childNodes.each { node ->
parent.appendChild( document.importNode( node, true ) )
}
}
else {
parent.appendChild( document.importNode( addCode, true ) )
}
}

Getting related entity count through FetchXML

I have the following fetchXML code for returning the total number of related entities. Main entity name is new_transaction and related entity name is new_transactionproduct.
The code below is placed in a web resource javascript but when this function is called it never gets to success or error portions, it simply hangs.
function countLineItems()
{
var ID = Xrm.Page.data.entity.getId();
var fetchXml = "<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false' aggregate='true'>";
fetchXml += "<entity name='new_transactionproduct'>";
fetchXml += "<attribute name='new_name' alias='recordcount' aggregate='countcolumn' />";
fetchXml += "<filter type='and'>";
fetchXml += "<condition attribute='new_transactionid' operator='eq' value='" + ID + "' />";
fetchXml += "</filter>";
fetchXml += "</entity>";
fetchXml += "</fetch>";
alert(fetchXml);
XrmSvcToolkit.fetch({
fetchXml: fetchXml,
async: false,
successCallback: function (result) {
var countValue = result.entities[0].recordcount;
alert(countValue);
//Xrm.Page.getAttribute(new_totalqty).setValue(countValue);
},
errorCallback: function (error) {
throw error;
}
});
}
Just a quick side note you could always setup your fetchXML like below to minimise the amound of times you append to the string.
string fetchXml = #"<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false' aggregate='true'>
<entity name='new_transactionproduct'>
<attribute name='new_name' alias='recordcount' aggregate='countcolumn' />
<filter type='and'>
<condition attribute='new_transactionid' operator='eq' value='" + ID + #"' />
</filter>
</entity>
</fetch>";
XrmSvcToolkit needed to be added as a web resource and referenced on the page.

Change XML tag name

I want to transform an XML document which I have parsed with XmlSlurper. The (identical) XML tag names should be replaced with the value of the id attribute; all other attributes should be dropped. Starting from this code:
def xml = """<tag id="root">
| <tag id="foo" other="blah" more="meh">
| <tag id="bar" other="huh"/>
| </tag>
|</tag>""".stripMargin()
def root = new XmlSlurper().parseText(xml)
// Some magic here.
println groovy.xml.XmlUtil.serialize(root)
I want to get the following:
<root>
<foo>
<bar/>
</foo>
</root>
(I write test assertions on the XML, and want to simplify the structure for them.) I've read Updating XML with XmlSlurper and searched around, but found no way with replaceNode() or replaceBody() to exchange a node while keeping its children.
Adding the 'magic' in to the code in the question gives:
def xml = """<tag id="root">
| <tag id="foo" other="blah" more="meh">
| <tag id="bar" other="huh"/>
| </tag>
|</tag>""".stripMargin()
def root = new XmlSlurper().parseText(xml)
root.breadthFirst().each { n ->
n.replaceNode {
"${n.#id}"( n.children() )
}
}
println groovy.xml.XmlUtil.serialize(root)
Which prints:
<?xml version="1.0" encoding="UTF-8"?><root>
<foo>
<bar/>
</foo>
</root>
HOWEVER, this will drop any content in the nodes. To maintain content, we would probably need to use recursion and XmlParser to generate a new doc from the existing one... I'll have a think
More general solution
I think this is more generalised:
import groovy.xml.*
def xml = """<tag id="root">
| <tag id="foo" other="blah" more="meh">
| <tag id="bar" other="huh">
| something
| </tag>
| <tag id="bar" other="huh">
| something else
| </tag>
| <noid>woo</noid>
| </tag>
|</tag>""".stripMargin()
def root = new XmlParser().parseText( xml )
def munge( builder, node ) {
if( node instanceof Node && node.children() ) {
builder."${node.#id ?: node.name()}" {
node.children().each {
munge( builder, it )
}
}
}
else {
if( node instanceof Node ) {
"${node.#id ?: node.name()}"()
}
else {
builder.mkp.yield node
}
}
}
def w = new StringWriter()
def builder = new MarkupBuilder( w )
munge( builder, root )
println XmlUtil.serialize( w.toString() )
And prints:
<?xml version="1.0" encoding="UTF-8"?><root>
<foo>
<bar>something</bar>
<bar>something else</bar>
<noid>woo</noid>
</foo>
</root>
Now passes through nodes with no (or empty) id attributes

Resources