Quantcast
Channel: XML, System.Xml, MSXML and XmlLite forum
Viewing all articles
Browse latest Browse all 935

Processing elements dynamically in XSLT

$
0
0

Hi,

I have a scenario where I have two node sets from which I will have to process the data, in the below code in the source XML I have two node sets - CONTENT1 and CONTENT2; I need to read this and generate a different XML out of this. I have the below code for this and this is working perfectly as expected.

Source XML:

<XMLContent><CONTENT1>
<DATA PRJTID="217" REGID="F_DATA">
  <CHILD PNUM="" PKID="" PKID1="" PKID2="" PName1="" PName2="" P_DOMFOR="" DP1="" DP2=""/>
  <CHILD PNUM="" PKID="" PKID1="" PKID2="" PName1="" PName2="" P_DOMFOR=""  DP1="" DP2=""/>
  <CHILD PNUM="" PKID="" PKID1="" PKID2="" PName1="" PName2="" P_DOMFOR=""  DP1="" DP2=""/>
  <CHILD PNUM="P No" PKID="P Key ID" PName1="Name Line 1" PName2="Name Line 2" P_DOMFOR="Domestic"  />
  <CHILD PNUM="ROUNDING VAL" PKID="" PKID2="" PName1="TOTALS" PName2="" P_DOMFOR=""  DP1="" DP2=""/>
  <CHILD PNUM="1" PKID="1" PKID1="" PKID2="" PName1="Name Line 1a" PName2="Name Line 1b"

P_DOMFOR="Domestic"  DP1="10" DP2="20"/>
  <CHILD PNUM="2" PKID="2" PKID1="" PKID2="" PName1="Name Line 2a" PName2="" P_DOMFOR="Foreign" 

DP1="100" DP2="200"/>
  <CHILD PNUM="3" PKID="3" PKID1="" PKID2="" PName1="First Middle Last" PName2="" P_DOMFOR="Domestic" 

DP1="1000" DP2="2000"/> 
</DATA></CONTENT1>

<CONTENT2>
<DATA PRJTID="217" REGID="PDI">
  <CHILD PNUM="1" PKID="" PKID1="" PKID2="" PName1="" PName2="" PName3="" PAdd1="" PAdd2="" PCity=""

PID="Form" />
  <CHILD PNUM="" PKID="" PKID1="" PKID2="" PName1="" PName2="" PName3="" PAdd1="" PAdd2="" PCity=""

PID="Line" />
  <CHILD PNUM="" PKID="" PKID1="" PKID2="" PName1="" PName2="" PName3="" PAdd1="" PAdd2="" PCity=""

PID="Code" />
  <CHILD PNUM="P No" PKID="PKey ID" PKID1="Other ID" PKID2="Other ID - 2" PName1="P Name Line 1"

PName2="P Name PAdd1="Street Address 1" PAdd2="Street Address 2" PCity="City" PID=""/>

  <CHILD PNUM="" PKID="PDetails" PKID1="" PKID2="" PName1="" PName2="" PName3="" PAdd1="" PAdd2=""

PCity="" PTD_USFORIND="" PTDI_ADDST="" PTDI_ADDZIP="" PID="Fund" PTDI_CUST5="" />

  <CHILD PNUM="1" PKID="1" PKID1="" PKID2="" PName1=" Name Line 1# " PName2="Name Line 1b" PName3=""

PAdd1=" 1 Mai$n S.t" PAdd2="Apt 1" PCity="NewCity" PID="1" />
  <CHILD PNUM="2" PKID="2" PKID1="" PKID2="" PName1="Name Line 2a" PName2="" PName3="" PAdd1="2 Main St"

PAdd2="" PCity="Berlin" PID="2" />
  <CHILD PNUM="3" PKID="3" PKID1="" PKID2="" PName1="First Middle Last" PName2="" PName3="" PAdd1="3

Main St" PAdd2="" PCity="Los Angeles" PID="3" /> 
</DATA></CONTENT2></XMLContent>

XSLT Code:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
    xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl"
>
  <xsl:output method="xml" indent="yes"/>

  <xsl:key name="PIR" match="//XMLContent/CONTENT2/DATA/CHILD" use="@PNUM"/>
 
  <xsl:param name="ParamPKeyName" select="''"/>
  <xsl:variable name="id-list" select="concat(',', $ParamPKeyName, ',')"/>

  <xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'" />
  <xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />


  <xsl:template match="/">
    <xsl:choose>
      <xsl:when test="$ParamPKeyName=''">
        <Return>
          <xsl:apply-templates select="XMLContent/CONTENT1/DATA/CHILD[string(number(@PNUM)) != 'NaN' and (@PNUM != '0')]"/>
        </Return>
      </xsl:when>
      <xsl:otherwise>
        <Return>
          <xsl:apply-templates select="XMLContent/CONTENT1/DATA/CHILD[(string(number(@PNUM)) != 'NaN') and (@PNUM != '') and contains($id-list, concat(',', @PNUM, ','))]"/>
        </Return>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>


  <xsl:template match="CHILD">
    <xsl:variable name="RecordNo">
      <xsl:value-of select="position()"/>
    </xsl:variable>

    <xsl:variable name="PNo" select="@PNUM"/>
 <Root>
  <ContentValues>
   <Name>
<xsl:value-of select="key('PIR', $PNo)/@PName1"/>
</Name>
   <City>
<xsl:value-of select="key('PIR', $PNo)/@PCity"/>
</City>
                        <Value1>
<xsl:value-of select="@DP1"/>
</Value1>
                         <Value2>
<xsl:value-of select="@DP2"/>
</Value2>
                </ContentValues>
        </Root>
  </xsl:template>
</xsl:stylesheet>

C# Code to call this:

In the below parameters: You can consider the follwing

first parameter - xml will take the sourcexml code mentioned above; path is the xslt file path; sPKId = 1,2,3

private string TransformXML(string xml, string Path, string sPKId)
        {
         
            //read XML
            TextReader tr1 = new StringReader(xml);
            XmlTextReader tr11 = new XmlTextReader(tr1);

            XPathDocument xPathDocument = new XPathDocument(tr11);

            //read XSLT
            XmlTextReader tr22 = new XmlTextReader(Path);
            XslCompiledTransform xslt = new XslCompiledTransform();

            xslt.Load(tr22);

            //create the output stream
            StringBuilder sb = new StringBuilder();
            TextWriter tw = new StringWriter(sb);

           
            XsltArgumentList args = new XsltArgumentList();
            args.AddParam("ParamPKeyName", "", sPKId);

           

            xslt.Transform(xPathDocument, args, tw);

         
            return sb.ToString();

                       
        }

The problem or what I am looking at is explained below:

If you see my Source XML, In Content1, the first few attributes will be the same, the attribute PNUM will be unique and this is what I am considering when I am mapping the two node sets in my XSLT(code above); if you look at my XSLT code; I am reading DP1 and DP2 attributes; in the current scenario I know that the attribute names will always be DP1 and DP2 and I have coded my XSLT accordingly; this is working fine; however in the scenario I am looking for there could be more attributes which might be present in the source and I need to read that; the first few attributes will remain the same and I would know them(PNUM="" PKID="" PKID1="" PKID2="" PName1="" PName2="" P_DOMFOR="") but from DP1 onwards it could be dynamic, and I need to pull the value for each of the dynamic attributes; like how I am pulling the value for DP1 and DP2 in my XSLT code; (my Content2 node set is not going to change at all), how to pull the attributes values dynamnically when I do not know; another issue is the code that I have now to pull the values for Name and City in XSLT will have to be there, and I need to additionaly handle this dynamic attributes. I am using XSLT 1.0 only and I can use this only.

I am not sure how to handle this scenario; could you please help me with this. I have re-created the code and if you see any mistakes, kindly apoligize. Looking forward for your help and advice.  

<XMLContent><CONTENT1>
<DATA PRJTID="217" REGID="F_DATA">
  <CHILD PNUM="" PKID="" PKID1="" PKID2="" PName1="" PName2="" P_DOMFOR="" DP1="" DP2=""/>
  <CHILD PNUM="" PKID="" PKID1="" PKID2="" PName1="" PName2="" P_DOMFOR=""  DP1="" DP2=""/>
  <CHILD PNUM="" PKID="" PKID1="" PKID2="" PName1="" PName2="" P_DOMFOR=""  DP1="" DP2=""/>
  <CHILD PNUM="P No" PKID="P Key ID" PName1="Name Line 1" PName2="Name Line 2" P_DOMFOR="Domestic"  />
  <CHILD PNUM="ROUNDING VAL" PKID="" PKID2="" PName1="TOTALS" PName2="" P_DOMFOR=""  DP1="" DP2=""/>
  <CHILD PNUM="1" PKID="1" PKID1="" PKID2="" PName1="Name Line 1a" PName2="Name Line 1b"

P_DOMFOR="Domestic"  DP1="10" DP2="20"/>
  <CHILD PNUM="2" PKID="2" PKID1="" PKID2="" PName1="Name Line 2a" PName2="" P_DOMFOR="Foreign" 

DP1="100" DP2="200"/>
  <CHILD PNUM="3" PKID="3" PKID1="" PKID2="" PName1="First Middle Last" PName2="" P_DOMFOR="Domestic" 

DP1="1000" DP2="2000"/> 
</DATA></CONTENT1>


Rpaul


Viewing all articles
Browse latest Browse all 935

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>