<Instance xsi:type="ButtonConfig">
<Name>ExitButton</Name>
<Height>89</Height>
<Width>120</Width>
<Margin>
<All>-1</All>
<Bottom>0</Bottom>
<Left>400</Left>
<Right>0</Right>
<Top>11</Top>
</Margin>
</Instance>
In the above xml, I need to change the Left Margin to 420. How do I do it using XSLT?
This is almost the “identify transform”, which simply duplicates the input document.
Here’s a simple stylesheet that mostly performs the identity transform, while overriding the output for a <Left/> within a <Margin/> within an <Instance/> that has a <Name/> containing ExitButton. Note that I had to add a namespace definition to your input XML for xsi, which I assume is elsewhere in the document.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Margin/Left[ancestor::Instance/Name[text()='ExitButton']]">
<Left>420</Left>
</xsl:template>
</xsl:stylesheet>
As any XSLT tutorial would tell you: For something simple like this, start with the identity stylesheet, which copies the document essentially unchanged... then add a template which implements the exception to that.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Margin/Left">
<xsl:copy>
<xsl:text>420</xsl:text>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Related
<?xml version="1.0" encoding="UTF-8"?>
<root>
<Interaction>
<RecipientId>666994250005</RecipientId>
<RecipientType>Normal</RecipientType>
<MailingId>18744460</MailingId>
<ReportId>2121196700</ReportId>
<CampaignId/>
<Email>ilovepizza#mntest.net</Email>
<EventType>HardBounce</EventType>
<EventTimestamp>05/11/202113:46:40</EventTimestamp>
<BodyType/>
<ContentId/>
<ClickName/>
<URL/>
<ConversionAction/>
<ConversionDetail/>
<ConversionAmount/>
<SuppressionReason/>
<MailingName>YourNovemberTrend-TESTING_682-BOUNCES</MailingName>
<MailingSubject>YourNovemberTrend-TESTING_682-BOUNCES</MailingSubject>
<CONTACT_MC_ID>42010A0351251EEBA0EF17B38C3EDC78</CONTACT_MC_ID>
<CAMPAIGN_ID>0000000682</CAMPAIGN_ID>
<SOURCE_OBJECT_ID>C01AFE8349D7F713787E25B656A3D2D6BA205205</SOURCE_OBJECT_ID>
<UUID>ca69251e-8b0e-1d90-1700-1c42c1610f6d</UUID>
</Interaction>
<Interaction>
<RecipientId>672386985145</RecipientId>
<RecipientType>Normal</RecipientType>
<MailingId>18848768</MailingId>
<ReportId>2141674081</ReportId>
<CampaignId/>
<Email>cg#gmail.com</Email>
<EventType>Sent</EventType>
<EventTimestamp>06/08/202119:28:06</EventTimestamp>
<BodyType/>
<ContentId/>
<ClickName/>
<URL/>
<ConversionAction/>
<ConversionDetail/>
<ConversionAmount/>
<SuppressionReason/>
<MailingName>TrendEmailTestSend425(18)</MailingName>
<MailingSubject>TESTING:YourNovemberTrend-710Campaign</MailingSubject>
<CONTACT_MC_ID>42010A0351251EDBA6904634DF983CB0</CONTACT_MC_ID>
<CAMPAIGN_ID>0000000710</CAMPAIGN_ID>
<SOURCE_OBJECT_ID>42948F6B87172477E4BE993B3EC48255EF4A27D4</SOURCE_OBJECT_ID>
<UUID>1292721e-8b0e-1d90-1700-1c42c1610f6d</UUID>
</Interaction>
</root>
I am trying below XSLT but it's not working:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/Interaction">
<xsl:if test="/root/Interaction/EventType/text() != 'HardBounce'">
<xsl:copy>
<xsl:copy-of select="#*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Output Expected is:
<root>
<Interaction>
<RecipientId>672386985145</RecipientId>
<RecipientType>Normal</RecipientType>
<MailingId>18848768</MailingId>
<ReportId>2141674081</ReportId>
<CampaignId/>
<Email>cg#gmail.com</Email>
<EventType>Sent</EventType>
<EventTimestamp>06/08/202119:28:06</EventTimestamp>
<BodyType/>
<ContentId/>
<ClickName/>
<URL/>
<ConversionAction/>
<ConversionDetail/>
<ConversionAmount/>
<SuppressionReason/>
<MailingName>TrendEmailTestSend425(18)</MailingName>
<MailingSubject>TESTING:YourNovemberTrend-710Campaign</MailingSubject>
<CONTACT_MC_ID>42010A0351251EDBA6904634DF983CB0</CONTACT_MC_ID>
<CAMPAIGN_ID>0000000710</CAMPAIGN_ID>
<SOURCE_OBJECT_ID>42948F6B87172477E4BE993B3EC48255EF4A27D4</SOURCE_OBJECT_ID>
<UUID>1292721e-8b0e-1d90-1700-1c42c1610f6d</UUID>
</Interaction>
</root>
Just dipping toe in XSLT. Thanks for help.
The node should be copied to target on meeting the condition.
Do not Read below. This is just to get the stack over
StackoverStackoverflow is asking me to put more details to question but i think i have provided enough details to comprehend the problem.
The instruction:
<xsl:template match="/root/Interaction">
puts you in the context of Interaction. From this context, the test of EventType needs to use the relative path to the EventType that is the child of the current Interaction - e.g.
<xsl:if test="EventType != 'HardBounce'">
What you have starts from the root and tests if there is at least one EventType that meets the condition in the entire XML document. This is of course true for all Interaction elements being tested.
Note that you could accomplish the same thing much more simply by:
<xsl:stylesheet version="3.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/root">
<xsl:copy>
<xsl:copy-of select="Interaction[EventType != 'HardBounce']"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Block the elements you don't want from being copied with an empty template <xsl:template match="Interaction[EventType = 'HardBounce']"/>. Handle the rest through your first template or even replace it by declaring <xsl:mode on-no-match="shallow-copy"/>, if you are using XSLT 3.
I have a .xsl file like this:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:exslt="http://exslt.org/common">
<xsl:template match="/>
<fo:root>
<fo:block>...</fo:block>
</fo:root>
</xsl:template>
</xsl:stylesheet>
How can I use templates to match and style the generated fo elements? For example, if I want to give my fo:table-cells red backgrounds, I'd like to be able to do
<xsl:template match="fo:table-cell">
<xsl:attribute name="background-color">red</xsl:attribute>
</xsl:template>
I found this and then tried something along the lines of
<xsl:template match="/>
<xsl:variable name="foRoot">
<fo:root>
<fo:block>...</fo:block>
</fo:root>
</xsl:variable>
<xsl:apply-templates select="exslt:node-set($foRoot)" />
</xsl:template>
but this results in a stack overflow due to endless recursion. When I try to avoid this, for example by doing
<xsl:apply-templates select="exslt:node-set($foRoot)/*" />
I get an empty document. When trying to fix that by adding
<xsl:copy-of select="$foRoot" />
right after, I don't get any errors but the table-cells still have a default white background.
If you really use an XSLT 2 processor then first of all you don't need exsl:node-set.
As for your template
<xsl:template match="fo:table-cell">
<xsl:attribute name="background-color">red</xsl:attribute>
</xsl:template>
that would match a FO table-cell but transform it into an attribute. So you rather want
<xsl:template match="fo:table-cell">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:attribute name="background-color">red</xsl:attribute>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
as that adds the attribute to a shallow copy of the element and then keeps processing alive for child elements with apply-templates.
Of course you will also need to add the identity transformation template
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
to make sure the elements you don't want to change are copied through. It might be necessary to use modes to separate processing steps if the other templates you have interfere with the identity transformation.
suppose I have following XML as source:
<ns0:msg xmlns:ns0="namespace0">
<ns0:hdr a_lot_of_attrs="value">
some nodes...
</ns0:hdr>
<ns0:body>
<ns0:data a_lot_of_attrs="value">
<ns1:purchase_order xmlns:ns1="namespace1">some nodes...</ns1:purchase_order>
</ns0:data>
</ns0:body>
</ns0:msg>
And I need following XML as the result:
<a:msg xmlns:a="namespace0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<a:hdr a_lot_of_attrs="value">
some nodes...
</a:hdr>
<a:body>
<a:data a_lot_of_attrs="value">
<b:purchase_order
xsi:schemaLocation="filelocation"
xmlns:b="namespace1"
xmlns:c="namespace2">some nodes...</b:purchase_order>
</a:data>
</a:body>
</a:msg>
Basically I need just to replace the namespace prefix ns0 into a and ns1 into b. Further more, the root element <a:msg> as well as the <b:purchase_order> need to be added by some additional attributes.
My attemp is by using following XSLT:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns0="namespace0"
xmlns:ns1="namespace1"
xmlns:a="namespace0"
xmlns:b="namespace1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
exclude-result-prefixes="ns0 ns1">
<xsl:output method="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<a:msg xmlns:msg="namespace1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<xsl:copy>
<xsl:apply-templates select="ns0:msg/*"/>
</xsl:copy>
</a:msg>
</xsl:template>
<xsl:template match="/ns0:msg/ns0:body/ns0:data/ns1:purchase_order">
<b:purchase_order xsi:schemaLocation="filelocation" xmlns:c="namespace2">
<xsl:copy>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</b:purchase_order>
</xsl:template>
<xsl:template match="ns0:*">
<xsl:element name="a:{local-name()}">
<xsl:apply-templates select="#* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="ns1:*">
<xsl:element name="b:{local-name()}">
<xsl:apply-templates select="#* | node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="#*">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
It works fine so far, except the node <purchase_order> has been populated 2 times:
<a:msg xmlns:a="namespace0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<a:hdr a_lot_of_attrs="value">
some nodes...
</a:hdr>
<a:body>
<a:data a_lot_of_attrs="value">
<b:purchase_order xmlns:b="namespace1" xmlns:c="namespace2" xsi:schemaLocation="filelocation">
<ns1:purchase_order xmlns:ns0="namespace0" xmlns:ns1="namespace1">some nodes...</ns1:purchase_order>
</b:purchase_order>
</a:data>
</a:body>
</a:msg>
I tried several times by tweaking the second <xsl:template> but could not get it right. Would someone pls advise where I get wrong here and how can I get this done?
Thanks a lot.
You current template that matches ns1:purchase_order contains an xsl:copy as well as the creation of the new b:purchase_order. Therefore you are copying the old node as well as creating a new one.
You can remove the xsl:copy from the template, like so:
<xsl:template match="ns1:purchase_order">
<b:purchase_order xsi:schemaLocation="filelocation" xmlns:c="namespace2">
<xsl:apply-templates select="node()"/>
</b:purchase_order>
</xsl:template>
Note that you don't necessarily have to specify the full path in the template match. You would only really need to do this if you had a second ns1:purchase_order in the XML, at a different location, that you didn't want to match.
I want to replace the element tag name using xslt. I have an output like this:
<gl-cor:documentInfo>
<gl-cor:entriesType contextRef="journal_context">DocumentID</gl-cor:entriesType>
<gl-cor:uniqueID contextRef="journal_context">RevisionID</gl-cor:uniqueID>
</gl-cor:documentInfo>
<gl-cor:entityInformation>
<gl-cor:entityPhoneNumber>
<gl-cor:phoneNumber contextRef="journal_context">779633</gl-cor:phoneNumber>
</gl-cor:entityPhoneNumber>
<gl-cor:entityFaxNumberStructure>
<gl-cor:entityFaxNumbercontextRef="journal_context">1234-56-89</gl-cor:entityFaxNumber>
</gl-cor:entityFaxNumberStructure>
</gl-cor:entityInformation>
And, I want my output to be looks like this:
<gl-cor:documentInfo>
<gl-cor:entriesType contextRef="journal_context">DocumentID</gl-cor:entriesType>
<gl-bus:uniqueID contextRef="journal_context">RevisionID</gl-cor:uniqueID>
</gl-cor:documentInfo>
<gl-cor:entityInformation>
<gl-bus:entityPhoneNumber>
<gl-bus:phoneNumber contextRef="journal_context">779633</gl-bus:phoneNumber>
</gl-bus:entityPhoneNumber>
<gl-bus:entityFaxNumberStructure>
<gl-bus:entityFaxNumbercontextRef="journal_context">1234-56-89</gl-bus:entityFaxNumber>
</gl-bus:entityFaxNumberStructure>
</gl-cor:entityInformation>
All the children of <gl-cor:entityInformation> should replace instead of gl-cor, it should be gl-bus. Is it possible to do this?
I tried to create a sample xslt but it didn't work. The error occurs in the <gl-bus:phoneNumber>, because I think it is contain a special characters? like "-" and ":".
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="gl-cor:entityInformation/gl-cor:entityPhoneNumber/gl-cor:phoneNumber">
<gl-bus:phoneNumber>
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</gl-bus:phoneNumber>
</xsl:template>
Can someone help me solve this problem? Thanks alot.
First of all gl-cor and gl-bus are namespace prefixes. Namespace prefixes are written before an XML element and seperated from the XML element with a :. So your problem is not because of the characters - and :, these are all valid characters, please also read these articles/tutorials:
http://www.w3schools.com/xml/xml_namespaces.asp
http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references#Predefined_entities_in_XML
To answer your problem we need to know what the namspace URIs are for gl-cor and gl-bus, but it should look like this:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:gl-cor="http://example.org/gl-cor" xmlns:gl-bus="http://example.org/gl-bus">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="*[ancestor::gl-cor:entityInformation]">
<xsl:element name="gl-bus:{local-name()}">
<xsl:apply-templates select="#*|node()" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
The template *[ancestor::gl-cor:entityInformation] will match on all (grand)children of gl-cor:entityInformation.
NOTE
The namespaces in the XSLT should be updated and match to your input XML:
xmlns:gl-cor="http://example.org/gl-cor"
xmlns:gl-bus="http://example.org/gl-bus"
We are trying to add two additional namespace/attributes in our XML file. The structure is an external definition (XSD) and we'd like to know if it would be possible if we can add two new attribute/namespaces via XSLT or this should be included in the external defintion? (Of course, updating the external defintion is the easiest way out.)
I've already looked at several questions here like:
adding attribute to the node
Adding namespace to child elements using xslt
XSLT transforming is throwing error
But I'm still clueless as to how to make this work. I'm a virgin with regard to XSLT - no experience at all. Would like to know if this is possible via XSLT.
As-is
<ns2:ProcessCommunication xmlns:ns2="http://URL">
<ns2:communication>
<ns2:CommunicationTemplateAbbreviation>INV</ns2:CommunicationTemplateAbbreviation>
<ns2:CommunicationValues>
<ns2:CommunicationValue>
<ns2:FinancialValue>205029</ns2:FinancialValue>
<ns2:Title>Net</ns2:Title>
</ns2:CommunicationValue>
</ns2:CommunicationValues>
<ns2:CustomFields>
<ns2:CustomField>
<ns2:Name>SomeValue</ns2:Name>
<ns2:Answer>
<ns2:Value>1</ns2:Value>
</ns2:Answer>
</ns2:CustomField>
<ns2:CustomField>
<ns2:Name>Transaction Currency</ns2:Name>
<ns2:Answer>
<ns2:Value>EUR</ns2:Value>
</ns2:Answer>
</ns2:CustomField>
</ns2:CustomFields>
</ns2:communication>
</ns2:ProcessCommunication>
To-be:
<ns2:ProcessCommunication xmlns:ns2="http://URL">
<ns2:communication>
<ns2:CommunicationTemplateAbbreviation>INV</ns2:CommunicationTemplateAbbreviation>
<ns2:CommunicationValues>
<ns2:CommunicationValue>
<ns2:FinancialValue>205029</ns2:FinancialValue>
<ns2:Title>Net</ns2:Title>
</ns2:CommunicationValue>
</ns2:CommunicationValues>
<ns2:CustomFields>
<ns2:CustomField>
<ns2:Name>SomeValue</ns2:Name>
<ns2:Answer>
<ns2:Value i:type="a:string" xmlns:a="http://www.w3.org/2001/XMLSchema">1</ns2:Value>
</ns2:Answer>
</ns2:CustomField>
<ns2:CustomField>
<ns2:Name>Transaction Currency</ns2:Name>
<ns2:Answer>
<ns2:Value i:type="a:string" xmlns:a="http://www.w3.org/2001/XMLSchema">EUR</ns2:Value>
</ns2:Answer>
</ns2:CustomField>
</ns2:CustomFields>
</ns2:communication>
</ns2:ProcessCommunication>
There's an additional
i:type="a:string" xmlns:a="http://www.w3.org/2001/XMLSchema"
in the node, Value.
I am only able to go until here, which is pretty useless.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance" >
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node()">
<xsl:copy>
<xsl:attribute name="i:type">a:string</xsl:attribute>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I try and use <xsl:template match="Answer/Value"> and this doesn't work.
You were just missing the namespace declaration on the XSLT itself. This should work:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns2="http://URL">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ns2:Answer/ns2:Value">
<xsl:copy>
<xsl:attribute name="i:type">a:string</xsl:attribute>
<xsl:attribute name="xmlns:a">http://www.w3.org/2001/XMLSchema</xsl:attribute>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>