xslt transformation in vba - excel

I am trying to generate an xml from a set of xpaths. This is related to Generating XML from xpath using xslt
I found a XSLT that may solve my problem in this answer to another question
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:my="my:my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:key name="kNSFor" match="namespace" use="#of"/>
<xsl:variable name="vStylesheet" select="document('')"/>
<xsl:variable name="vPop" as="element()*">
<item path="/create/article/#type">richtext</item>
<item path="/create/article/#lang">en-us</item>
<item path="/create/article[1]/id">1</item>
<item path="/create/article[1]/description">bar</item>
<item path="/create/article[1]/name[1]">foo</item>
<item path="/create/article[1]/price[1]/amount">00.00</item>
<item path="/create/article[1]/price[1]/currency">USD</item>
<item path="/create/article[1]/price[2]/amount">11.11</item>
<item path="/create/article[1]/price[2]/currency">AUD</item>
<item path="/create/article[2]/id">2</item>
<item path="/create/article[2]/description">some name</item>
<item path="/create/article[2]/name[1]">some description</item>
<item path="/create/article[2]/price[1]/amount">00.01</item>
<item path="/create/article[2]/price[1]/currency">USD</item>
<namespace of="create" prefix="ns1:"
url="http://predic8.com/wsdl/material/ArticleService/1/"/>
<namespace of="article" prefix="ns1:"
url="xmlns:ns1='http://predic8.com/material/1/"/>
<namespace of="#lang" prefix="xml:"
url="http://www.w3.org/XML/1998/namespace"/>
<namespace of="price" prefix="ns1:"
url="xmlns:ns1='http://predic8.com/material/1/"/>
<namespace of="id" prefix="ns1:"
url="xmlns:ns1='http://predic8.com/material/1/"/>
</xsl:variable>
<xsl:template match="/">
<xsl:sequence select="my:subTree($vPop/#path/concat(.,'/',string(..)))"/>
</xsl:template>
<xsl:function name="my:subTree" as="node()*">
<xsl:param name="pPaths" as="xs:string*"/>
<xsl:for-each-group select="$pPaths" group-adjacent=
"substring-before(substring-after(concat(., '/'), '/'), '/')">
<xsl:if test="current-grouping-key()">
<xsl:choose>
<xsl:when test=
"substring-after(current-group()[1], current-grouping-key())">
<xsl:variable name="vLocal-name" select=
"substring-before(concat(current-grouping-key(), '['), '[')"/>
<xsl:variable name="vNamespace"
select="key('kNSFor', $vLocal-name, $vStylesheet)"/>
<xsl:choose>
<xsl:when test="starts-with($vLocal-name, '#')">
<xsl:attribute name=
"{$vNamespace/#prefix}{substring($vLocal-name,2)}"
namespace="{$vNamespace/#url}">
<xsl:value-of select=
"substring(
substring-after(current-group(), current-grouping-key()),
2
)"/>
</xsl:attribute>
</xsl:when>
<xsl:otherwise>
<xsl:element name="{$vNamespace/#prefix}{$vLocal-name}"
namespace="{$vNamespace/#url}">
<xsl:sequence select=
"my:subTree(for $s in current-group()
return
concat('/',substring-after(substring($s, 2),'/'))
)
"/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="current-grouping-key()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:for-each-group>
</xsl:function>
</xsl:stylesheet>
I am trying to transform this in VBA using code from http://www.oreillynet.com/xml/blog/2005/04/transforming_xml_in_microsoft.html
I got an error
Private Sub Transform(sourceFile, stylesheetFile, resultFile)
Dim source As New MSXML2.DOMDocument30
Dim stylesheet As New MSXML2.DOMDocument30
Dim result As New MSXML2.DOMDocument30
' Load data.
source.async = False
source.Load sourceFile
' Load style sheet.
stylesheet.async = False
stylesheet.Load stylesheetFile
If (source.parseError.ErrorCode <> 0) Then
MsgBox ("Error loading source document: " & source.parseError.reason)
Else
If (stylesheet.parseError.ErrorCode <> 0) Then
MsgBox ("Error loading stylesheet document: " & stylesheet.parseError.reason)
Else
' Do the transform.
source.transformNodeToObject stylesheet, result
result.Save resultFile
End If
End If
End Sub
I also tried to use transformNode instead to transformNodeToObject. I got
object doesn't support this property or method
Private Sub Transform(sourceFile, stylesheetFile, resultFile)
Dim source As New MSXML2.DOMDocument60
Dim stylesheet As New MSXML2.DOMDocument60
Dim result As New MSXML2.DOMDocument60
' Load data
source.async = False
source.Load sourceFile
' Load style sheet.
stylesheet.async = False
stylesheet.Load stylesheetFile
If (source.parseError.ErrorCode <> 0) Then
MsgBox ("Error loading source document: " & source.parseError.reason)
Else
If (stylesheet.parseError.ErrorCode <> 0) Then
MsgBox ("Error loading stylesheet document: " & stylesheet.parseError.reason)
Else
' Do the transform.
source.transformNode (stylesheet)
'result.Save resultFile
End If
End If
End Sub

Related

Find and ReplaceAll : To get Find Value in Attribute and Replace with Content using XSLT3.0

I would like to do Find and Replace using XSLT 3.0. When I have found the value from TextStyle element with attribute of FONTSTYLE value it should store in variables and replace with the text.
Found Pattern is : <String ID="p1_w5" CONTENT="Human" HPOS="261.948" VPOS="75.8759" STYLEREFS="font1"/>
Replace Pattern Expect this : <String ID="p1_w5" CONTENT="<bold>Human</bold>" HPOS="261.948" VPOS="75.8759" STYLEREFS="font1"/>
How do achieve my requirements using XSLT Find and Replace?
My Current Input XML File is :
<?xml version="1.0" encoding="UTF-8"?>
<ALTO>
<STYLES>
<TextStyle ID="font1" FONTFAMILY="cambria" FONTSIZE="12.000" FONTSTYLE="bold"/>
<TextStyle ID="font2" FONTFAMILY="cambria" FONTSIZE="7.920" FONTSTYLE="sup"/>
<TextStyle ID="font3" FONTFAMILY="cambria" FONTSIZE="12.000" FONTSTYLE="it"/>
</STYLES>
<LAYOUT>
<TextBlock ID="p1_b1" HPOS="83.6703" VPOS="75.8759" HEIGHT="10.6680" WIDTH="445.700">
<TextLine WIDTH="445.700" HEIGHT="10.6680" ID="p1_t1" HPOS="83.6703" VPOS="75.8759">
<String ID="p1_w1" CONTENT="Hie" HPOS="83.6703" VPOS="75.8759" STYLEREFS="font0"/>
<String ID="p1_w2" CONTENT="org" HPOS="154.915" VPOS="75.8759" STYLEREFS="font0"/>
<String ID="p1_w3" CONTENT="of" HPOS="228.005" VPOS="75.8759" STYLEREFS="font0"/>
<String ID="p1_w4" CONTENT="the" HPOS="241.393" VPOS="75.8759" STYLEREFS="font0"/>
<String ID="p1_w5" CONTENT="Human" HPOS="261.948" VPOS="75.8759" STYLEREFS="font1"/>
<String ID="p1_w6" CONTENT="cell" HPOS="303.263" VPOS="75.8759" STYLEREFS="font0"/>
<String ID="p1_w8" CONTENT="a" HPOS="354.900" VPOS="75.8759" STYLEREFS="font0"/>
<String ID="p1_w9" CONTENT="CANCER" HPOS="363.965" VPOS="75.8759" STYLEREFS="font3"/>
</TextLine>
</TextBlock>
</LAYOUT>
</ALTO>
Tried XSLT file :
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fnc="http://www.xsweet.org/2022/ext"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl"
exclude-result-prefixes="#all"
version="3.0">
<xsl:output method="xml" indent="yes"/>
<xsl:preserve-space elements="*"/>
<xsl:template match="/|node()|*|#*">
<xsl:copy>
<xsl:apply-templates select="node() | * | #*"/>
</xsl:copy>
</xsl:template>
<xsl:param name="styletag1" select="TextStyle[#FONTSTYLE = 'sup']"/>
<xsl:param name="styletag2" select="TextStyle[#FONTSTYLE = 'it']"/>
<xsl:param name="styletag3" select="TextStyle[#FONTSTYLE = 'bold']"/>
<xsl:template match="/|node()|*|#*">
<xsl:copy>
<xsl:apply-templates select="node() | * | #*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="LAYOUT/TextBlock/TextLine/String[$styletag1]">
<xsl:message>Superscript Need to Replace All</xsl:message>
</xsl:template>
</xsl:stylesheet>
You can do
<xsl:key name="text-style" match="TextStyle/#FONTSTYLE" use="../#ID"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:template match="String[key('text-style', #STYLEREFS)]/#CONTENT">
<xsl:attribute name="{name()}" select="'<' || key('text-style', ../#STYLEREFS) || '>' || . || '</' || key('text-style', ../#STYLEREFS) || '>'"/>
</xsl:template>
but of course the output is XML with entity references in the attribute value e.g.
<String ID="p1_w5" CONTENT="<bold>Human</bold>" HPOS="261.948" VPOS="75.8759" STYLEREFS="font1"/>
If you really want e.g. CONTENT="<bold>Human</bold>" then use a character map
<xsl:output use-character-maps="m1"/>
<xsl:character-map name="m1">
<xsl:output-character character="<" string="<"/>
<xsl:output-character character=">" string=">"/>
</xsl:character-map>

XSLT Can't Read an Excel XML File?

I'm using XSLT / XPath to browse some of the XML files you get when you unzip an Excel file. I found a "relationships" file workbook.xml.rels that I don't seem to be able to read, using code similar to that which successfully read the workbook.xml file.
Here's some of the workbook.xml file:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
...
<sheets>
<sheet name="Sheet1"
sheetId="2"
r:id="rId1"/>
<sheet name="Test Sheet"
sheetId="1"
r:id="rId2"/>
</sheets>
...
</workbook>
Here's the workbook.xml.rels file:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId3"
Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme"
Target="theme/theme1.xml"/>
<Relationship Id="rId2"
Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"
Target="worksheets/sheet2.xml"/>
<Relationship Id="rId1"
Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"
Target="worksheets/sheet1.xml"/>
<Relationship Id="rId5"
Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"
Target="sharedStrings.xml"/>
<Relationship Id="rId4"
Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"
Target="styles.xml"/>
</Relationships>
Here's some of the XSLT:
<?xml version="1.0"?>
<!-- greeting.xsl -->
<xsl:stylesheet
...
<xsl:output method="text"/>
<xsl:variable name="baseDir" select="replace(document-uri(.), '(.*[\\/]xl).*', '$1/')"/>
<xsl:variable name="workbook" select="concat($baseDir, 'workbook.xml')"/>
<xsl:variable name="theSheetId" select="doc($workbook)/workbook/sheets/sheet[matches(#name, 'Test Sheet')]/#r:id"/>
<xsl:variable name="workbook_rels" select="concat($baseDir, '_rels/workbook.xml.rels')"/>
<!-- code to read workbook.xml.rels -->
<xsl:variable name="theSheet" select="doc($workbook_rels)/Relationships/Relationship[matches(#Id, $theSheetId)]/#Target"/>
<xsl:template match="/">
<xsl:text>
baseDir = </xsl:text><xsl:value-of select="$baseDir"/>
<xsl:text>
workbook = </xsl:text><xsl:value-of select="$workbook"/>
<xsl:text>
workbook_rels = </xsl:text><xsl:value-of select="$workbook_rels"/>
<xsl:text>
theSheetId = </xsl:text><xsl:value-of select="$theSheetId"/>
<xsl:text>
theSheet = </xsl:text><xsl:value-of select="$theSheet"/>
<xsl:text>
end</xsl:text>
</xsl:template>
</xsl:stylesheet>
And the output:
baseDir = file:/C:/Training/sandbox/conv_/xl/
workbook = file:/C:/Training/sandbox/conv_/xl/workbook.xml
workbook_rels = file:/C:/Training/sandbox/conv_/xl/_rels/workbook.xml.rels
theSheetId = rId2
theSheet = **<I get nothing here>**
end
You can see that 'theSheetID' variable is correctly set when reading workbook.xml. But when I use that variable to get the corresponding Target value into 'theSheet' variable from workbook.xml.rels, I get nothing. I tried replacing the matches expression with just a number but I still get nothing. Is there a problem from reading this type of file?
Suggestions? Thanks!
The use of matches and replace suggests you are using an XSLT 2 or 3 processor and that way XSLT 2 or 3 where you can certainly declare xpath-default-namespace, you just have to understand you have to change that in the sections that deal with elements from a different namespace e.g. <xsl:variable name="theSheet" select="doc($workbook_rels)/Relationships/Relationship[matches(#Id, $theSheetId)]/#Target" xpath-default-namespace="http://schemas.openxmlformats.org/package/2006/relationships"/>.
Given the samples I would rather use a key <xsl:key name="rel" match="Relationships/Relationship" use="#Id" xpath-default-namespace="http://schemas.openxmlformats.org/package/2006/relationships"/> and then use <xsl:variable name="theSheet" select="key('rel,$theSheetId, doc($workbook_rels))/#Target"/> but the use of xpath-default-namespace to declare the relevant namespace when selecting elements from a particular document is probably what is missing in your XSLT.

How to change this VBA/XSLT-based code so the output is written in a single XML-File

I got the following code as a result of a previous question.
The meaning of the code was to iterate through an excelsheet and automatically fill XML-tags with cell contents. The Output was a XML-File for every ROW in this excelsheet.
Now I have a very similar case and I know, that it can't be a lot to change to get it done. I want my code NOT to create a new XML-File for every row, but to fill everything in the same XML-File.
I want to automatically fill in the content of this excel-table:
into an XML-Template that initially looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<Codes>
<AreaCodes>
<Area>
<Name></Name>
<Desc/>
<Facility_Area></Facility_Area>
</Area>
</AreaCodes>
</Codes>
The column FACILITY has to be moved in the Facility_Area-Tag.
The column AREA has to be moved in the Name-Tag.
All the nested tags inside of Area should be repeated.
For my Excel-Example the output should look like this:
<?xml version="1.0" encoding="UTF-8"?>
<Codes>
<AreaCodes>
<Area>
<Name>RA 001</Name>
<Desc/>
<Facility_Area>ZUF</Facility_Area>
</Area>
<Area>
<Name>RA 002</Name>
<Desc/>
<Facility_Area>ZUF</Facility_Area>
</Area>
<Area>
<Name>RA 003</Name>
<Desc/>
<Facility_Area>ZUF</Facility_Area>
</Area>
<Area>
<Name>RA 004</Name>
<Desc/>
<Facility_Area>ZUF</Facility_Area>
</Area>
...
</AreaCodes>
</Codes>
all in one file.
This is the XSLT-Template I have atm:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:param name="facility" />
<xsl:param name="area" />
<!-- IDENTITY TRANSFORM -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<!-- Templates -->
<xsl:template match="Codes/AreaCodes/Area/Name">
<xsl:copy>
<xsl:value-of select="$area"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Codes/AreaCodes/Area/Facility_Area">
<xsl:copy>
<xsl:value-of select="$facility"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
and last but not least the VBA-Code in which everything comes together:
Sub Param_XSLT_Process()
...
' LOAD XML AND XSL FILES
xmldoc.async = False
xmldoc.Load "Path\To\Vorlage_AREA.xml"
xslDoc.async = False
xslDoc.setProperty "AllowDocumentFunction", True
xslDoc.Load "Path\To\XSL_SHEET.xsl"
' INITIALIZE NEEDED OBJECTS
Set xslTemp.stylesheet = xslDoc
Set xslProc = xslTemp.createProcessor()
xslProc.input = xmldoc
' ITERATE THROUGH EACH ROW, TRANSFORM, SAVE XML OUTPUT
With ActiveWorkbook.Worksheets(1)
lLastRow = .UsedRange.Rows.Count
For lRow = 2 To lLastRow
xslProc.addParameter "area", CStr(.Cells(lRow, 2).Value) ' ADD PARAMETER(S)
xslProc.addParameter "facility", CStr(.Cells(lRow, 1).Value)
xslProc.transform ' TRANSFORM XML
newDoc.LoadXML xslProc.output ' LOAD RESULT TREE
newDoc.Save "Path\To\Output_" & lRow - 1 & ".xml" ' SAVE OUTPUT TO FILE
Next lRow
End With
...
End Sub
Right now, everything is dropped in a separate XML-File.
Could anyone tell me, what i have to change? I know that, for my VBA-Code, I should move those save-commands outside of the loop, but that doesn't work.
Sorry for struggling with English and thank you all for your help.
I wrote a VBA class module SheetWrapper:
Private mySheet As Object
Sub Init(sheet)
Set mySheet = sheet
End Sub
Public Property Get Cell(rowIndex, cellIndex)
Cell = CStr(mySheet.Cells(rowIndex, cellIndex).Value)
End Property
Then it is possible to use
Sub Param_XSLT_Process()
Dim xmlDoc As New MSXML2.DOMDocument60
Dim xslDoc As New MSXML2.FreeThreadedDOMDocument60
Dim xslTemp As New MSXML2.XSLTemplate60
Dim xslProc As MSXML2.IXSLProcessor
Dim resultDoc As New MSXML2.DOMDocument60
Dim worksheet As Object
Set worksheet = ActiveWorkbook.Worksheets(1)
Dim myWrapper As SheetWrapper
Set myWrapper = New SheetWrapper
myWrapper.Init worksheet
' LOAD XML AND XSL FILES
xmlDoc.async = False
xmlDoc.Load "C:\SomePath\template.xml"
xslDoc.async = False
xslDoc.SetProperty "AllowDocumentFunction", True
xslDoc.Load "C:\SomePath\sheet.xsl"
' INITIALIZE NEEDED OBJECTS
Set xslTemp.stylesheet = xslDoc
Set xslProc = xslTemp.createProcessor()
xslProc.addObject myWrapper, "http://example.com/excel"
xslProc.addParameter "first-row-index", 2, ""
xslProc.addParameter "last-row-index", ActiveWorkbook.Worksheets(1).UsedRange.Rows.Count, ""
xslProc.input = xmlDoc
xslProc.output = resultDoc
xslProc.transform
resultDoc.Save "C:\SomePath\transformation-result.xml"
End Sub
together with the XSLT:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:excel="http://example.com/excel"
exclude-result-prefixes="msxsl excel">
<xsl:param name="sheet"/>
<xsl:param name="first-row-index"/>
<xsl:param name="last-row-index"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:output indent="yes"/>
<xsl:template match="AreaCodes">
<xsl:copy>
<xsl:call-template name="make-areas">
<xsl:with-param name="area" select="Area"/>
<xsl:with-param name="index" select="$first-row-index"/>
<xsl:with-param name="last" select="$last-row-index"/>
</xsl:call-template>
</xsl:copy>
</xsl:template>
<xsl:template name="make-areas">
<xsl:param name="area"/>
<xsl:param name="index"/>
<xsl:param name="last"/>
<xsl:apply-templates select="$area">
<xsl:with-param name="row-index" select="$index"/>
</xsl:apply-templates>
<xsl:if test="$index < $last">
<xsl:call-template name="make-areas">
<xsl:with-param name="area" select="$area"/>
<xsl:with-param name="index" select="$index + 1"/>
<xsl:with-param name="last" select="$last"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template match="Area">
<xsl:param name="row-index"/>
<xsl:copy>
<xsl:apply-templates>
<xsl:with-param name="row-index" select="$row-index"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="Area/Name">
<xsl:param name="row-index"/>
<xsl:copy>
<xsl:value-of select="excel:get-Cell($row-index, 1)"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Area/Facility_Area">
<xsl:param name="row-index"/>
<xsl:copy>
<xsl:value-of select="excel:get-Cell($row-index, 2)"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I had hoped to be able to pass the Excel sheet object directly to XSLT to read out its cells but somehow MSXML didn't grok that.

removing namespace in node level

below is my input xml code
<?xml version="1.0" encoding="UTF-8"?>
<EPCISDocument xmlns:ns1="http://apse.com" schemaVersion="" creationDate="">
<EPCISHeader>
<StandardBusinessDocumentHeader>
<HeaderVersion/>
<Sender>
<Identifier Authority=""/>
<ContactInformation>
<Contact/>
<EmailAddress/>
<FaxNumber/>
<TelephoneNumber/>
<ContactTypeIdentifier/>
</ContactInformation>
</Sender>
<Receiver>
<Identifier Authority=""/>
<ContactInformation>
<Contact/>
<EmailAddress/>
<FaxNumber/>
<TelephoneNumber/>
<ContactTypeIdentifier/>
</ContactInformation>
</Receiver>
<Manifest>
<NumberOfItems/>
<ManifestItem>
<MimeTypeQualifierCode/>
<UniformResourceIdentifier/>
<Description/>
<LanguageCode/>
</ManifestItem>
</Manifest>
<BusinessScope>
<Scope>
<BusinessService>
<BusinessServiceName/>
<ServiceTransaction TypeOfServiceTransaction="" IsNonRepudiationRequired="" IsAuthenticationRequired="" IsNonRepudiationOfReceiptRequired="" IsIntegrityCheckRequired="" IsApplicationErrorResponseRequired="" TimeToAcknowledgeReceipt="" TimeToAcknowledgeAcceptance="" TimeToPerform=""/>
</BusinessService>
<CorrelationInformation>
<RequestingDocumentCreationDateTime/>
<RequestingDocumentInstanceIdentifier/>
<ExpectedResponseDateTime/>
</CorrelationInformation>
</Scope>
</BusinessScope>
</StandardBusinessDocumentHeader>
</EPCISHeader>
<EPCISBody>
<EventList>
<ObjectEvent>
<eventTime/>
<recordTime/>
<eventTimeZoneOffset/>
<epcList>
<epc type=""/>
</epcList>
<action/>
<bizStep/>
<disposition/>
<readPoint>
<id/>
</readPoint>
<bizLocation>
<id/>
</bizLocation>
<bizTransactionList>
<bizTransaction type=""/>
</bizTransactionList>
<GskEpcExtension>
<manufacturingDate>1234</manufacturingDate>
</GskEpcExtension>
</ObjectEvent>
</EventList>
</EPCISBody>
</EPCISDocument>
I want to add some prefixes, so I have applied below xslt code which got from stackoverflow and it is working fine. but with below code I am getting namespaces in node level.below is the xsl code.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:gsk="http://apse.com">
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="GskEpcExtension|GskEpcExtension//*">
<xsl:element name="gsk:{name()}" namespace="http://epcis.gsk.com">
<xsl:copy-of select="namespace::*"/>
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
<xsl:template match="StandardBusinessDocumentHeader|StandardBusinessDocumentHeader//*">
<xsl:element name="sbdh:{name()}" namespace="http://www.unece.org/cefact/namespaces/StandardBusinessDocumentHeader">
<xsl:copy-of select="namespace::*"/>
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
output for this xsl code is
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="Untitled3.xslt"?>
<EPCISDocument xmlns:ns1="http://apse.com" schemaVersion="" creationDate="">
<EPCISHeader>
<sbdh:StandardBusinessDocumentHeader xmlns:sbdh="http://www.unece.org/cefact/namespaces/StandardBusinessDocumentHeader">
<sbdh:HeaderVersion/>
<sbdh:Sender>
<sbdh:Identifier Authority=""/>
<sbdh:ContactInformation>
<sbdh:Contact/>
<sbdh:EmailAddress/>
<sbdh:FaxNumber/>
<sbdh:TelephoneNumber/>
<sbdh:ContactTypeIdentifier/>
</sbdh:ContactInformation>
</sbdh:Sender>
<sbdh:Receiver>
<sbdh:Identifier Authority=""/>
<sbdh:ContactInformation>
<sbdh:Contact/>
<sbdh:EmailAddress/>
<sbdh:FaxNumber/>
<sbdh:TelephoneNumber/>
<sbdh:ContactTypeIdentifier/>
</sbdh:ContactInformation>
</sbdh:Receiver>
<sbdh:Manifest>
<sbdh:NumberOfItems/>
<sbdh:ManifestItem>
<sbdh:MimeTypeQualifierCode/>
<sbdh:UniformResourceIdentifier/>
<sbdh:Description/>
<sbdh:LanguageCode/>
</sbdh:ManifestItem>
</sbdh:Manifest>
<sbdh:BusinessScope>
<sbdh:Scope>
<sbdh:BusinessService>
<sbdh:BusinessServiceName/>
<sbdh:ServiceTransaction TypeOfServiceTransaction="" IsNonRepudiationRequired="" IsAuthenticationRequired="" IsNonRepudiationOfReceiptRequired="" IsIntegrityCheckRequired="" IsApplicationErrorResponseRequired="" TimeToAcknowledgeReceipt="" TimeToAcknowledgeAcceptance="" TimeToPerform=""/>
</sbdh:BusinessService>
<sbdh:CorrelationInformation>
<sbdh:RequestingDocumentCreationDateTime/>
<sbdh:RequestingDocumentInstanceIdentifier/>
<sbdh:ExpectedResponseDateTime/>
</sbdh:CorrelationInformation>
</sbdh:Scope>
</sbdh:BusinessScope>
</sbdh:StandardBusinessDocumentHeader>
</EPCISHeader>
<EPCISBody>
<EventList>
<ObjectEvent>
<eventTime/>
<recordTime/>
<eventTimeZoneOffset/>
<epcList>
<epc type=""/>
</epcList>
<action/>
<bizStep/>
<disposition/>
<readPoint>
<id/>
</readPoint>
<bizLocation>
<id/>
</bizLocation>
<bizTransactionList>
<bizTransaction type=""/>
</bizTransactionList>
<gsk:GskEpcExtension xmlns:gsk="http://epcis.gsk.com">
<gsk:manufacturingDate>1234</gsk:manufacturingDate>
</gsk:GskEpcExtension>
</ObjectEvent>
in the output payload for gskepcextension and standardbusinessdocuemnt header the namespaces are appearing but I need the output in below format for both nodes and the entire output structure is mentioned below. please check and help on this.
<?xml version="1.0" encoding="UTF-8"?>
<epcis:EPCISDocument xmlns:epcis="urn:epcglobal:epcis:xsd:1" xmlns:sbdh="http://www.unece.org/cefact/namespaces/StandardBusinessDocumentHeader" xmlns:gsk="http://epcis.gsk.com" schemaVersion="1.0" creationDate="2013-05-16T13:23:36Z" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
<EPCISHeader>
<sbdh:StandardBusinessDocumentHeader>
<sbdh:HeaderVersion/>
<sbdh:Sender>
<sbdh:Identifier Authority="String">5051150024380</sbdh:Identifier>
<!-- This is optional information -->
<sbdh:ContactInformation>
<sbdh:Contact>String</sbdh:Contact>
<sbdh:EmailAddress>String</sbdh:EmailAddress>
<sbdh:FaxNumber>String</sbdh:FaxNumber>
<sbdh:TelephoneNumber>String</sbdh:TelephoneNumber>
<sbdh:ContactTypeIdentifier>String</sbdh:ContactTypeIdentifier>
</sbdh:ContactInformation>
</sbdh:Sender>
<sbdh:Receiver>
<sbdh:Identifier Authority="String">5051150018624</sbdh:Identifier>
<!-- This is optional information -->
<sbdh:ContactInformation>
<sbdh:Contact>String</sbdh:Contact>
<sbdh:EmailAddress>String</sbdh:EmailAddress>
<sbdh:FaxNumber>String</sbdh:FaxNumber>
<sbdh:TelephoneNumber>String</sbdh:TelephoneNumber>
<sbdh:ContactTypeIdentifier>String</sbdh:ContactTypeIdentifier>
</sbdh:ContactInformation>
</sbdh:Receiver>
<sbdh:DocumentIdentification>
<sbdh:Standard/>
<sbdh:TypeVersion/>
<sbdh:InstanceIdentifier>39cf981e070111e6838b0000362219a6</sbdh:InstanceIdentifier>
<sbdh:Type/>
<sbdh:CreationDateAndTime>2001-12-17T09:30:47Z</sbdh:CreationDateAndTime>
</sbdh:DocumentIdentification>
</sbdh:StandardBusinessDocumentHeader>
</EPCISHeader>
<EPCISBody>
<EventList>
<ObjectEvent>
<eventTime>2015-10-21T17:31:12.1530000+00:00</eventTime>
<eventTimeZoneOffset>+02:00</eventTimeZoneOffset>
<epcList>
<epc>urn:epc:id:sgtin:8806500.000122.2F52DTV751</epc>
<epc>urn:epc:id:sgtin:8806500.000122.23037KDFCV</epc>
<epc>urn:epc:id:sgtin:8806500.000122.2RPZF7GAAB</epc>
<epc>urn:epc:id:sgtin:8806500.000122.2HSWA43EV2</epc>
<epc>urn:epc:id:sgtin:8806500.000122.2S0Z8P3VHV</epc>
</epcList>
<action>ADD</action>
<bizStep>urn:epcglobal:cbv:bizstep:commissioning</bizStep>
<disposition>urn:epcglobal:cbv:disp:active</disposition>
<bizLocation>
<id>urn:epc:id:sgln:4028685.00000.0</id>
</bizLocation>
<gsk:GskEpcExtension>
<gsk:additionalTradeItemIdentificationValue>199610</gsk:additionalTradeItemIdentificationValue>
<gsk:lotNumber>15L011</gsk:lotNumber>
<gsk:itemExpirationDate>20171006</gsk:itemExpirationDate>
<gsk:manufacturingDate/>
<gsk:gtin>08806500001224</gsk:gtin>
<gsk:nhrn> </gsk:nhrn>
</gsk:GskEpcExtension>
</ObjectEvent>
</EventList>
</EPCISBody>
</epcis:EPCISDocument>
It seems you only need to add one more template:
<xsl:template match="EPCISDocument">
<epcis:EPCISDocument xmlns:epcis="urn:epcglobal:epcis:xsd:1">
<xsl:apply-templates select="node()|#*"/>
</epcis:EPCISDocument>
</xsl:template>
I would also suggest moving all your namespace declarations to the top level element, so that eventually your stylesheet looks something like:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:epcis="urn:epcglobal:epcis:xsd:1"
xmlns:sbdh="http://www.unece.org/cefact/namespaces/StandardBusinessDocumentHeader"
xmlns:gsk="http://epcis.gsk.com">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="EPCISDocument">
<epcis:EPCISDocument>
<xsl:apply-templates select="node()|#*"/>
</epcis:EPCISDocument>
</xsl:template>
<xsl:template match="GskEpcExtension|GskEpcExtension//*">
<xsl:element name="gsk:{name()}">
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
<xsl:template match="StandardBusinessDocumentHeader|StandardBusinessDocumentHeader//*">
<xsl:element name="sbdh:{name()}">
<xsl:apply-templates select="node()|#*"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>

Xstl global variable set in for each and used after foreach

First of all, I'm new to XSLT.
I'm working with Sharepoint list and I need to get a link to show up if there's data in specific quarters. If there's no data in a certain quarter, I need to have a label that says so.
So what I did is that i created a foreach loop for each data of the same Month of a given year.I know that i cannot re-assing a variable in xslt but I dont know how to do what I want.
Here's a sample of my code. Since I'm working with Sharepoint i dont have acces to the XML. :/
<xsl:variable name="DataQ1" select="'False'"/>
<xsl:variable name="DataQ2" select="'False'"/>
<xsl:variable name="DataQ3" select="'False'"/>
<xsl:variable name="DataQ4" select="'False'"/>
<xsl:for-each select="../Row[generate-id()=generate-id(key('MonthKey', substring(#Date,6,7))[substring('#Date',1,4) = $varYear)][1])]">
<xsl:variable name="currentMonth" select="number(substring(#Date,6,7))"/>
<xsl:choose>
<xsl:when test="$currentMonth >= 1 and $currentMonth $lt;=4">
<!--set $DataQ1 to true-->
</xsl:when>
<xsl:when test="$currentMonth >= 4 and $currentMonth $lt;=7">
<!--set $DataQ2 to true-->
</xsl:when>
<xsl:when test="$currentMonth >= 7 and $currentMonth $lt;=10">
<!--set $DataQ3 to true-->
</xsl:when>
<xsl:otherwise>
<!--set $DataQ4 to true-->
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
<div>
<xsl:choose>
<xsl:when test="$DataQ1= 'True'">
<a>
<xsl:attribute name="href">
<xsl:value-of select="www.example.come"/>
</xsl:attribute>
<xsl:value-of select="'LinkToDataofQ1'"/>
</a>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'There's no data for this quarter.'"/>
</xsl:otherwise>
</xsl:choose>
</div>
You use the key function in your example code but you didn't post the declaration of your key. But I think you can achieve what you want with the following code:
<div>
<xsl:choose>
<xsl:when test="../Row[substring(#Date, 1, 4) = $varYear and substring(#Date, 6, 2) >= 1 and substring(#Date, 6, 2) < 4]">
LinkToDataofQ1
</xsl:when>
<xsl:otherwise>There's no data for this quarter.</xsl:otherwise>
</xsl:choose>
</div>
Some other notes:
In your test for Q1 you wrote $currentMonth <= 4. I think what you want is $currentMonth < 4.
To extract the month from #Date you used substring(#Date, 6, 7). The third argument to substring is the length of the substring, not the end index. So you'll probably should write substring(#Date, 6, 2).
Instead of <xsl:value-of select="'string'"/>, you can simply write string.

Resources