flatten XML nested node with XSLT

goal : import a CRM dynamics odata xml file into SSIS XML transformation block.

SSIS contraints :

  • only one namespace
  • no nested nodes
  • remove "un necessary" link node

simplified xml source

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<feed xml:base="https://XXXXXXXXXX/XRMServices/2011/OrganizationData.svc/" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">
  <title type="text">allianceSet</title>
  <entry>
    <link rel="edit" title="be_alliance" href="be_allianceSet(guid'429352cb-deca-e311-80c0-00155d5682af')" />
    <link rel="XXXX" type="application/atom+xml;type=entry" title="lk_be_alliance_createdby" href="be_allianceSet/lk_be_alliance_createdby" />
    <link rel="XXXX" type="application/atom+xml;type=entry" title="lk_be_alliance_createdonbehalfby" href="be_allianceSet(/lk_be_alliance_createdonbehalfby" />
    <content type="application/xml">
      <m:properties>
        <d:ModifiedOn m:type="Edm.DateTime">2015-10-30T13:06:31Z</d:ModifiedOn>
        <d:CreatedBy m:type="Microsoft.Crm.Sdk.Data.Services.EntityReference" m:null="true">
          <d:Id m:type="Edm.Guid">40f20074-ede3-48cc-aafc-750a1275b99b</d:Id>
          <d:LogicalName>systemuser</d:LogicalName>
        </d:CreatedBy>
        <d:statecode m:type="Microsoft.Crm.Sdk.Data.Services.OptionSetValue">
          <d:Value m:type="Edm.Int32">0</d:Value>
        </d:statecode>
      </m:properties>
    </content>
  </entry>
</feed>

XSL input 1.0

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output indent="yes" method="xml" encoding="utf-8" omit-xml-declaration="yes"/>

    <xsl:template match="*[name() != 'link']">
        <xsl:element name="{local-name()}">
            <xsl:apply-templates select="@* | node()"/>
        </xsl:element>
    </xsl:template>

    <!-- template to copy attributes -->
    <xsl:template match="@*">
        <xsl:attribute name="{local-name()}">
            <xsl:value-of select="."/>
        </xsl:attribute>
    </xsl:template>
</xsl:stylesheet>

above xsl perfectly remove namespaces. however I'm trying to transform/flatten each node of type="Microsoft.Crm.Sdk.Data.Services.EntityReference" with only one guid value

...    
<CreatedBy type="Microsoft.Crm.Sdk.Data.Services.EntityReference" null="true">
    <Id type="Edm.Guid">40f20074-ede3-48cc-aafc-750a1275b99b</Id>
    <LogicalName>systemuser</LogicalName>
    </CreatedBy>
...

into

...
    <CreatedBy>40f20074-ede3-48cc-aafc-750a1275b99b</CreatedBy>
...

so far without any luck ... any help appreciated

Answers


It looks like you are avoiding trying to reference any specific namespace in your XSLT. If so, to match node with a a type attribute of "Microsoft.Crm.Sdk.Data.Services.EntityReference", you would have a template match like this:

<xsl:template match="*[@*[local-name() = 'type']='Microsoft.Crm.Sdk.Data.Services.EntityReference']">

Try this XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" method="xml" encoding="utf-8" omit-xml-declaration="yes"/>

    <xsl:template match="*">
        <xsl:element name="{local-name()}">
            <xsl:apply-templates select="@* | node()"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="*[local-name() = 'link']" />

    <xsl:template match="*[@*[local-name() = 'type']='Microsoft.Crm.Sdk.Data.Services.EntityReference']">
        <xsl:element name="{local-name()}">
            <xsl:value-of select="*[local-name() = 'Id']" />
        </xsl:element>
    </xsl:template>

    <!-- template to copy attributes -->
    <xsl:template match="@*">
        <xsl:attribute name="{local-name()}">
            <xsl:value-of select="."/>
        </xsl:attribute>
    </xsl:template>
</xsl:stylesheet>

Note how I have created a separate template to remove the link elements. With your current XSLT, the link element will actually be matched by XSLT's built-in templates, which would output any text nodes under link if there were any (which might not be the case for you, but might be better to code for it).

Of course, if you were dealing with XML documents with the same namespaces all the time, you could reference these in your XSLT, like so, which is slightly neater:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" 
    xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
    xmlns:atom="http://www.w3.org/2005/Atom">

    <xsl:output indent="yes" method="xml" encoding="utf-8" omit-xml-declaration="yes"/>

    <xsl:template match="*">
        <xsl:element name="{local-name()}">
            <xsl:apply-templates select="@* | node()"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="atom:link" />

    <xsl:template match="*[@m:type='Microsoft.Crm.Sdk.Data.Services.EntityReference']">
        <xsl:element name="{local-name()}">
            <xsl:value-of select="d:Id" />
        </xsl:element>
    </xsl:template>

    <!-- template to copy attributes -->
    <xsl:template match="@*">
        <xsl:attribute name="{local-name()}">
            <xsl:value-of select="."/>
        </xsl:attribute>
    </xsl:template>
</xsl:stylesheet>

Need Your Help

Background music xcode 7 swift

audio background swift2 xcode7

I´ve already made an app but now I want to play background audio in my app when it launch with endless loop. I know it´s a dumb question but I would be happy if anybody can help me. Thanks in advan...

Use registers without preserving them? (assembly)

windows assembly x86-64 cpu-registers win64

After the Windows calling convetion, only RAX,RCX,RDX,r8 and r9 can be used without having to preserve them (called volatile) and the rest are called nonvolatile (must be preserved).