XMLSlartlet Grep xml node and replace - xmlstarlet

how to find blocks of node and replace by custom block using xmlstarlet
Below my xml sample:
<?xml version="1.0" encoding="UTF-8"?>
<job>
<input>
<par_denominator nil="true"/>
<par_follow_source>true</par_follow_source>
<par_numerator nil="true"/>
<deblock_enable>Auto</deblock_enable>
<deblock_strength>0</deblock_strength>
<no_psi>false</no_psi>
</input>
<h264_settings>
<par_denominator nil="true"/>
<par_follow_source>true</par_follow_source>
<par_numerator nil="true"/>
</h264_settings>
</job>
I'd like to replace all the block contains
<par_denominator nil="true"/>
<par_follow_source>true</par_follow_source>
<par_numerator nil="true"/>
replacement value
<par_denominator>1</par_denominator>
<par_follow_source>false</par_follow_source>
<par_numerator>1</par_numerator>

xmlstarlet solution:
xmlstarlet ed -u '//*["par_denominator" or "par_numerator"][#nil="true"]' -v 1 \
-u '//par_follow_source[.="true"]' -v 'false' \
-d '//*["par_denominator" or "par_numerator"]/#nil' input.xml
The output:
<?xml version="1.0" encoding="UTF-8"?>
<job>
<input>
<par_denominator>1</par_denominator>
<par_follow_source>false</par_follow_source>
<par_numerator>1</par_numerator>
<deblock_enable>Auto</deblock_enable>
<deblock_strength>0</deblock_strength>
<no_psi>false</no_psi>
</input>
<h264_settings>
<par_denominator>1</par_denominator>
<par_follow_source>false</par_follow_source>
<par_numerator>1</par_numerator>
</h264_settings>
</job>

Related

access multiple elements of same XML at different depths to convert to R tibble

I have a fairly deep xml file of travel data that I've anonymized here. I would like to pull out the coupon statuses for multiple segments and attach them to the itinerary id. I'm having a very difficult time using the xml2 package and I think the reason why is that some of my XML data terminates with text and some terminate with attributes. I've tried to convert the xml to a list with as_list(). I've also tried to start with xml_find_all() but get a nodeset of 0 regardless of the node I search for (Ticketing or Coupons should work, for example). Below is the data:
<?xml version="1.0" encoding="UTF-8"?>
<eTicketCouponRS xmlns="http://webse" xmlns:ns4="http://s" xmlns:stl="http://se" Version="2.0.0">
<stl:ApplicationResults status="Complete">
<stl:Success timeStamp="2021-06-16T11:39:52-05:00" />
</stl:ApplicationResults>
<TicketingInfos>
<TicketingInfo>
<Ticketing AgencyCity="DCA" AgentWorkArea="A" IATA_Number="0952" IssuingAgent="A" PrimeHostID="1S" PseudoCityCode="5SE0" TransactionDateTime="2021-06-16T11:39">
<CouponData InformationSource="S" IssueDate="2021-03-29" NumBooklets="1" TicketMedia="E" TicketMode="63">
<AirItineraryPricingInfo>
<FareCalculation>
<Text>SAN AA X/E/DFW AA TYO M0.00NUC0.00END ROE1.00 XFSAN4.5DFW4.5</Text>
</FareCalculation>
<ItinTotalFare>
<BaseFare Amount="0.00" CurrencyCode="USD" />
<Taxes>
<Tax Amount="19.10" TaxCode="US" />
<Tax Amount="5.60" TaxCode="AY" />
<Tax Amount="9.00" TaxCode="XF" />
</Taxes>
<TotalFare Amount=".70" CurrencyCode="USD" />
</ItinTotalFare>
<PassengerTypeQuantity Code="GV1" />
</AirItineraryPricingInfo>
<Coupons>
<Coupon CodedStatus="OK" Number="1" StatusCode="RFND">
<FlightSegment DepartureDateTime="2021-08-13T06:15" FlightNumber="2535" RPH="1" ResBookDesigCode="V">
<DestinationLocation LocationCode="DFW" />
<FareBasis Code="VCA" />
<MarketingAirline Code="AA" FlightNumber="2535" />
<OperatingAirline Code="AA" />
<OriginLocation LocationCode="SAN" />
</FlightSegment>
</Coupon>
<Coupon CodedStatus="OK" Number="2" StatusCode="RFND">
<FlightSegment ConnectionInd="X" DepartureDateTime="2021-08-13T12:20" FlightNumber="175" RPH="2" ResBookDesigCode="V">
<DestinationLocation LocationCode="HND" />
<FareBasis Code="VCA" />
<MarketingAirline Code="AA" FlightNumber="175" />
<OperatingAirline Code="AA" />
<OriginLocation LocationCode="DFW" />
<FareTypeClass>PG</FareTypeClass>
<FareTypeRule>OW-GO</FareTypeRule>
</FlightSegment>
</Coupon>
</Coupons>
<CustomerInfo>
<Customer>
<Invoice Number="126" />
<Payment ApprovalID="03" RPH="1" ReferenceNumber="XXXXXXXXXXXX" Type="CC">
<CC_Info>
<PaymentCard Code="VI" ExpirationDate="XX-XX" />
</CC_Info>
</Payment>
<PersonName NameReference="PCS" PassengerType="GV1">
<GivenName>VER</GivenName>
<Surname>DE</Surname>
</PersonName>
</Customer>
</CustomerInfo>
<ItineraryRef CustomerIdentifier="R5" ID="EXAMPLE" />
</CouponData>
</Ticketing>
</TicketingInfo>
</TicketingInfos>
</eTicketCouponRS>
I have about 100 of these each to load separately and pull out a small table consisting of the following columns:
SuccTimeStamp TransacTimeStamp ItineraryID CouponNumber StatusCode Origin Destination OperatingAirline FlightNumber.
You can see that each of these elements are found at different depths of the xml and every travel itinerary has a different number of coupons, anywhere from 1-10. I also found a helpful post here from hrbrmstr helping out someone from 2018, but I can't get a similar solution to "see" my nodes and I'm not sure if it's my code or my xml data.
Any help is appreciated!
For nested XML files which you need to flatten for end use needs such as R, consider XSLT, the special-purpose language designed to transform XML files. You can run XSLT 1.0 scripts in R using the xslt package (sister to xml2). Alternatively, you can use a dedicated XSLT processor and have R call the external program with system(). Like SQL, XSLT is an industry, portable language not limited to R.
Within XSLT, since your granularity is coupon, you can extract from <Coupon> level and use the ancestor:: XPath axe to retrieve higher up level information. Due to the default namespace needs, the long-windeed <xsl:element> is used. IATA_Number is assumed to be ItineraryID.
XSLT (save as .xsl file, a special .xml file)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:w="http://webse"
xmlns:stl="http://se">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/w:eTicketCouponRS">
<xsl:copy>
<xsl:apply-templates select="descendant::w:Coupon"/>
</xsl:copy>
</xsl:template>
<xsl:template match="w:Coupon">
<xsl:copy>
<xsl:element name="SuccTimeStamp" namespace="http://webse">
<xsl:value-of select="ancestor::w:eTicketCouponRS/stl:ApplicationResults/stl:Success/#timeStamp"/>
</xsl:element>
<xsl:element name="TransacTimeStamp" namespace="http://webse">
<xsl:value-of select="ancestor::w:Ticketing/#TransactionDateTime"/>
</xsl:element>
<xsl:element name="ItineraryID" namespace="http://webse">
<xsl:value-of select="ancestor::w:Ticketing/#IATA_Number"/>
</xsl:element>
<xsl:element name="CouponNumber" namespace="http://webse">
<xsl:value-of select="#Number"/>
</xsl:element>
<xsl:element name="StatusCode" namespace="http://webse">
<xsl:value-of select="#CodedStatus"/>
</xsl:element>
<xsl:element name="Origin" namespace="http://webse">
<xsl:value-of select="w:FlightSegment/w:OriginLocation/#LocationCode"/>
</xsl:element>
<xsl:element name="Destination" namespace="http://webse">
<xsl:value-of select="w:FlightSegment/w:DestinationLocation/#LocationCode"/>
</xsl:element>
<xsl:element name="OperatingAirline" namespace="http://webse">
<xsl:value-of select="w:FlightSegment/w:OperatingAirline/#Code"/>
</xsl:element>
<xsl:element name="FlightNumber" namespace="http://webse">
<xsl:value-of select="w:FlightSegment/#FlightNumber"/>
</xsl:element>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Online Demo
R
library(xml2)
library(xslt)
# LOAD XML AND XSLT
doc <- read_xml("/path/to/Input.xml")
style <- read_xml("/path/to/Style.xsl", package = "xslt")
# RUN TRANSFORMATION AND SEE OUTPUT
flat_xml <- xml_xslt(doc, style)
cat(as.character(flat_xml))
# RETRIEVE data NODES
nmsp <- c(w = "http://webse")
recs <- xml2::xml_find_all(flat_xml, "//w:Coupon", ns=nmsp)
# BIND EACH CHILD TEXT AND NAME
df_list <- lapply(recs, function(r) {
vals <- xml2::xml_children(r)
data.frame(rbind(setNames(c(xml2::xml_text(vals)),
c(xml2::xml_name(vals)))))
})
# COMBINE ALL DFS
final_df <- do.call(rbind.data.frame, df_list)
rm(recs, df_list)
final_df
# SuccTimeStamp TransacTimeStamp ItineraryID CouponNumber StatusCode Origin Destination OperatingAirline FlightNumber
# 1 2021-06-16T11:39:52-05:00 2021-06-16T11:39 0952 1 OK SAN DFW AA 2535
# 2 2021-06-16T11:39:52-05:00 2021-06-16T11:39 0952 2 OK DFW HND AA 175
Above runs for a single XML. For 100 separate files, wrap above in a user-defined method and run lapply for a list of XML dataframes for master concatenation at very end. Load XSLT once outside loop since it does not change, assuming XML files retain same structure.
style <- read_xml("/path/to/Style.xsl", package = "xslt")
xml_to_df <- function(xml_file) { ... }
xml_dfs <- lapply(list_of_xml_files, xml_to_df)
master_df <- do.call(rbind.data.frame, xml_dfs)
Thanks Parfait! I was able to modify the template xsl that you provided. The xsl sheet seems to "parse" everything nicely! After I got it "flattened", all I simply had to do was as_list(), as_tibble() and unnest() a couple of times and then it was a data frame.
Thanks!

xmlstarlet Update Value Same Element value

I would like to update the second value of the element block.
The problem that I'm having the two blocks with same element structure.
My goal is to update the second block of
1. /job/input/audio_selector/track
2. /job/stream_assembly/audio_description/language_code
Here is what I tried.
xmlstarlet edit -L \
--update "//job/input//audio_selector/audio_selector/track" \
--value "3,4" \
--update "//job/stream_assembly//audio_description/audio_description/language_code" \
--value "french" payload.xml
Here is my xml:
<?xml version="1.0" encoding="UTF-8"?>
<job href="/jobs/24883">
<input>
<deblock_enable>Auto</deblock_enable>
<deblock_strength>0</deblock_strength>
<no_psi>false</no_psi>
<order>1</order>
<timecode_source>zerobased</timecode_source>
<file_input>
<certificate_file nil="true"/>
<password>xxx</password>
<uri>source</uri>
<username>xxx</username>
</file_input>
<name>input_1</name>
<video_selector>
<color_space>follow</color_space>
<order>1</order>
<program_id nil="true"/>
<name>input_1_video_selector_0</name>
</video_selector>
<audio_selector>
<default_selection>true</default_selection>
<infer_external_filename>false</infer_external_filename>
<order>1</order>
<program_selection>1</program_selection>
<selector_type>track</selector_type>
<track>1</track>
<unwrap_smpte337>true</unwrap_smpte337>
<name>input_1_audio_selector_0</name>
</audio_selector>
<audio_selector>
<default_selection>false</default_selection>
<infer_external_filename>false</infer_external_filename>
<order>2</order>
<program_selection>1</program_selection>
<selector_type>track</selector_type>
<track>UPDATE THIS</track>
<unwrap_smpte337>true</unwrap_smpte337>
<name>input_1_audio_selector_1</name>
</audio_selector>
</input>
<timecode_config>
<require_initial_timecode>false</require_initial_timecode>
<source>zerobased</source>
<sync_threshold nil="true"/>
</timecode_config>
<ad_trigger>scte35_splice_insert</ad_trigger>
<ad_avail_offset>0</ad_avail_offset>
<priority>100</priority>
<user_data/>
<avsync_enable>true</avsync_enable>
<avsync_pad_trim_audio>true</avsync_pad_trim_audio>
<stream_assembly>
<name>stream_assembly_0</name>
<video_description>
<afd_signaling>None</afd_signaling>
<anti_alias>true</anti_alias>
<drop_frame_timecode>true</drop_frame_timecode>
<fixed_afd nil="true"/>
<force_cpu_encode>false</force_cpu_encode>
<height>1080</height>
<insert_color_metadata>false</insert_color_metadata>
<respond_to_afd>None</respond_to_afd>
<sharpness>50</sharpness>
<stretch_to_output>false</stretch_to_output>
<timecode_passthrough>false</timecode_passthrough>
<vbi_passthrough>false</vbi_passthrough>
<width>1920</width>
<h264_settings>
<adaptive_quantization>medium</adaptive_quantization>
<bitrate>14000000</bitrate>
<buf_fill_pct nil="true"/>
<buf_size nil="true"/>
<cabac>true</cabac>
<flicker_reduction>off</flicker_reduction>
<force_field_pictures>false</force_field_pictures>
<framerate_denominator nil="true"/>
<framerate_follow_source>true</framerate_follow_source>
<framerate_numerator nil="true"/>
<gop_b_reference>false</gop_b_reference>
<gop_closed_cadence>1</gop_closed_cadence>
<gop_markers>false</gop_markers>
<gop_num_b_frames>2</gop_num_b_frames>
<gop_size>50.0</gop_size>
<gop_size_units>frames</gop_size_units>
<interpolate_frc>false</interpolate_frc>
<look_ahead_rate_control>medium</look_ahead_rate_control>
<max_bitrate nil="true"/>
<max_qp nil="true"/>
<min_buf_occ nil="true"/>
<min_i_interval>0</min_i_interval>
<min_qp nil="true"/>
<num_ref_frames>1</num_ref_frames>
<par_denominator nil="true"/>
<par_follow_source>true</par_follow_source>
<par_numerator nil="true"/>
<passes>1</passes>
<qp nil="true"/>
<repeat_pps>false</repeat_pps>
<rp2027_syntax>false</rp2027_syntax>
<scd>true</scd>
<sei_timecode>false</sei_timecode>
<slices>1</slices>
<slow_pal>false</slow_pal>
<softness nil="true"/>
<svq>0</svq>
<telecine>None</telecine>
<level>4.1</level>
<profile>High</profile>
<rate_control_mode>CBR</rate_control_mode>
<gop_mode>fixed</gop_mode>
<interlace_mode>progressive</interlace_mode>
</h264_settings>
<selected_gpu nil="true"/>
<codec>h.264</codec>
</video_description>
<audio_description>
<audio_type>0</audio_type>
<follow_input_audio_type>false</follow_input_audio_type>
<follow_input_language_code>false</follow_input_language_code>
<language_code>English</language_code>
<order>1</order>
<stream_name nil="true"/>
<timecode_passthrough>false</timecode_passthrough>
<aac_settings>
<ad_broadcaster_mix>false</ad_broadcaster_mix>
<bitrate>192000</bitrate>
<coding_mode>2_0</coding_mode>
<latm_loas>false</latm_loas>
<mpeg2>false</mpeg2>
<sample_rate>48000</sample_rate>
<profile>LC</profile>
<rate_control_mode>CBR</rate_control_mode>
</aac_settings>
<codec>aac</codec>
<audio_source_name>Audio Selector 1</audio_source_name>
</audio_description>
<audio_description>
<audio_type>0</audio_type>
<follow_input_audio_type>false</follow_input_audio_type>
<follow_input_language_code>false</follow_input_language_code>
<language_code>UPDATE THIS</language_code>
<order>2</order>
<stream_name nil="true"/>
<timecode_passthrough>false</timecode_passthrough>
<aac_settings>
<ad_broadcaster_mix>false</ad_broadcaster_mix>
<bitrate>192000</bitrate>
<coding_mode>2_0</coding_mode>
<latm_loas>false</latm_loas>
<mpeg2>false</mpeg2>
<sample_rate>48000</sample_rate>
<profile>LC</profile>
<rate_control_mode>CBR</rate_control_mode>
</aac_settings>
<codec>aac</codec>
<audio_source_name>Audio Selector 2</audio_source_name>
</audio_description>
</stream_assembly>
<output_group>
<custom_name>file_group_4</custom_name>
<name nil="true"/>
<order>1</order>
<file_group_settings>
<rollover_interval nil="true"/>
<destination>
<password>xxx</password>
<username>xxx</username>
<uri>destination</uri>
</destination>
</file_group_settings>
<type>file_group_settings</type>
<output>
<description nil="true"/>
<extension>mov</extension>
<log_edit_points>false</log_edit_points>
<name_modifier/>
<order>1</order>
<mov_settings>
<growing_reference>false</growing_reference>
<include_clap>false</include_clap>
<include_cslg>true</include_cslg>
<omneon_padding>true</omneon_padding>
<reference>self_contained</reference>
<write_xdcam>false</write_xdcam>
</mov_settings>
<stream_assembly_name>stream_assembly_0</stream_assembly_name>
<container>mov</container>
</output>
</output_group>
</job>
I'm new using xmlstarlet I tried everything but still I can't get it right.
I hope somebody will help.
Thank you very much
xmlstarlet solution:
xmlstarlet ed -L -u "//job/input/audio_selector[2]/track" -v "3,4" \
-u "//job/stream_assembly/audio_description[2]/language_code" -v "french" payload.xml
...audio_selector[2] - select the 2nd node among audio_selector tags

How to show all XSL elements?

The XML file contains Accounts and a list of Account (contains ID and AccountDescription).
In the below example, there are 2 Account.
<?xml version="1.0"?>
<Accounts>
<Account>
<ID>5</ID>
<AccountDescription>Account Description 5</AccountDescription>
</Account>
<Account>
<ID>8</ID>
<AccountDescription>Account Description 8</AccountDescription>
</Account>
</Accounts>
When using the below XSL, it creates a PDF file with 2 pages, and each page has the header ID and AccountDescription, but there is no data/content underneath it, like this:
On page 1:
ID AccountDescription
On page 2:
ID AccountDescription
I would like to show the data like this:
ID AccountDescription
5 Account Description 5
8 Account Description 8
How can I do that ? Thank you.
This is my current XSL:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:template match="Accounts">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master
master-name="main"
margin-top="0px"
margin-bottom="0px"
margin-left="18px"
margin-right="18px">
<fo:region-body margin-top="0.75in" margin-bottom="2in" margin-left="18px" margin-right="18px"/>
<fo:region-before extent="0.75in"/>
<fo:region-after extent="1.5in"/>
<fo:region-end extent="75px"/>
</fo:simple-page-master>
</fo:layout-master-set>
<xsl:apply-templates select="Account"/>
</fo:root>
</xsl:template>
<xsl:template match="Account">
<fo:page-sequence master-reference="main">
<fo:flow flow-name="xsl-region-body">
<fo:table font-size="10pt">
<fo:table-column column-width="15mm"/>
<fo:table-column column-width="55mm"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell >
<fo:block text-align="right"><xsl:value-of select="ID"/></fo:block>
</fo:table-cell>
<fo:table-cell >
<fo:block text-align="right"><xsl:value-of select="AccountDescription"/></fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</fo:flow>
</fo:page-sequence>
</xsl:template>
</xsl:stylesheet>
How can I show all data in the same page ?
You need to use only one fo:page-sequence. Move it from the Account template up into the Accounts template.
Updated XSLT
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:template match="Accounts">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master
master-name="main"
margin-top="0px"
margin-bottom="0px"
margin-left="18px"
margin-right="18px">
<fo:region-body margin-top="0.75in" margin-bottom="2in" margin-left="18px" margin-right="18px"/>
<fo:region-before extent="0.75in"/>
<fo:region-after extent="1.5in"/>
<fo:region-end extent="75px"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="main">
<fo:flow flow-name="xsl-region-body">
<xsl:apply-templates select="Account"/>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
<xsl:template match="Account">
<fo:table font-size="10pt">
<fo:table-column column-width="15mm"/>
<fo:table-column column-width="55mm"/>
<fo:table-body>
<fo:table-row>
<fo:table-cell >
<fo:block text-align="right"><xsl:value-of select="ID"/></fo:block>
</fo:table-cell>
<fo:table-cell >
<fo:block text-align="right"><xsl:value-of select="AccountDescription"/></fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
</xsl:template>
</xsl:stylesheet>

BizTalk Mapper: Link between siblings

I have the following XML that I need to transform:
<?xml version="1.0" encoding="utf-8"?>
<TestRecords>
<TestData>
<Users>
<User>
<Id>BG123</Id>
<Name>Bill Gates</Name>
</User>
<User>
<Id>SN123</Id>
<Name>Satya Nadella</Name>
</User>
</Users>
<UserDetails>
<UserDetail>
<UserId>SN123</UserId>
<CompanyName>Microsoft Corp</CompanyName>
</UserDetail>
<UserDetail>
<UserId>
<UserId>BG123</UserId>
<CompanyName>Bill Gates Foundation</CompanyName>
</UserId>
</UserDetail>
</UserDetails>
I need to map this XML into the following XML:
<?xml version="1.0" encoding="utf-8"?>
<TestRecords>
<TestData>
<Users>
<User>
<Id>BG123</Id>
<Name>Bill Gates</Name>
<CompanyName>Bill Gates Foundation</CompanyName>
</User>
<User>
<Id>SN123</Id>
<Name>Satya Nadella</Name>
<CompanyName>Microsoft Corp</CompanyName>
</User>
</Users>
</TestData>
</TestRecords>
When I loop over Users/User, I need to find the UserDetail where UserDetail/UserId is equal to the current User/Id
Thank you and best regards
Michael
If you don't want to do Custom XSLT as suggested by FCR the only other option when you have different looping structures is to have an intermediate schema and two maps.
Which produces
<TestRecords>
<TestData>
<Users>
<User>
<Id>BG123</Id>
<Name>Bill Gates</Name>
<UserDetails>
<UserID>SN123</UserID>
<CompanyName>Microsoft Corp</CompanyName>
</UserDetails>
<UserDetails>
<UserID>BG123</UserID>
<CompanyName>Bill Gates Foundation</CompanyName>
</UserDetails>
</User>
<User>
<Id>SN123</Id>
<Name>Satya Nadella</Name>
<UserDetails>
<UserID>SN123</UserID>
<CompanyName>Microsoft Corp</CompanyName>
</UserDetails>
<UserDetails>
<UserID>BG123</UserID>
<CompanyName>Bill Gates Foundation</CompanyName>
</UserDetails>
</User>
</Users>
</TestData>
</TestRecords>
Which you can then run through this second map to produce the desired outcome.
This will become very inefficient however if the second list is large.
This is a common lookup pattern in xslt and there is also the opportunity to use xsl:key to create an index which can boost performance on large documents. Refer here if you need to convert a .btm to xslt.
(Also, I'm assuming that there isn't a double wrapper UserId at on the last UserDetails/UserDetail element):
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output indent="yes"/>
<xsl:key name="userLookup"
match="/TestRecords/TestData/UserDetails/UserDetail" use="UserId"/>
<!--identity template - copy everything by default -->
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<!--i.e.match only Users in the first Users/User tree. Actually the explicit
ancestor qualifier is redundant because of the other suppress template -->
<xsl:template match="User[ancestor::Users]">
<User>
<xsl:copy-of select="child::*" />
<CompanyName>
<xsl:value-of select="key('userLookup', Id)/CompanyName"/>
</CompanyName>
</User>
</xsl:template>
<!--Suppress the second userdetails part of the tree entirely -->
<xsl:template match="UserDetails" />
</xsl:stylesheet>
Fiddle here

XML to XSL transform

I'm a newbie at XSL / XML. I would like to make a simple XSL of the below XML code, that just shows the attributes name and adress? I have most of the XSL but I can't write the part where it shows my results (the customers).
This is the XML code:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="customer.xsl"?>
<customers xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="customer.xsd">
<customer name="Jay Z" address="New York, trinity st. 300, USA"/>
<customer name="Vladimir Putin" address="St. Petersburg, wadim street 23, Russia"/>
<customer name="Hiro Nakamura" address="Kyoto, Natsukawa street 49, Japan"/>
</customers>
Like this?
<xsl:value-of select="customers/customer"/>
Any help will be much appreciated! Thank you.
The XSL itself would look like the following:
<xsl:for-each select="customers/customer">
<xsl:value-of select="#name"/>
<xsl:value-of select="#address"/>
</xsl:for-each>
This code as working example
For a more detailed example look at this

Resources