on 08-24-2010 7:05 PM
Dear SAP experts,
Would you be able to help me in configuring the right xslt code to accomodate the looping logic?
Source Document:
School (occur only once)
- Name (can occur multiple times)
- Nickname (occur only once)
- Desired name (occur only once)
Target Document:
School
- Name
- Nickname (the value for this should be obtained from 'Desired name field')
- Desired name
I have this code, but seems not working in looping logic. (to accomodate the multiple Names):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" media-type="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Order/OrderDetail/ListOfItemDetail/ItemDetail/BaseItemDetail/ItemIdentifiers/PartNumbers/BuyerPartNumber">
<BuyerPartNumber>
<PartNum>
<PartID>
<xsl:value-of select ="/Order/OrderDetail/ListOfItemDetail/ItemDetail/BaseItemDetail/ItemIdentifiers/PartNumbers/ManufacturerPartNumber/PartID"/>
</PartID>
</PartNum>
</BuyerPartNumber>
</xsl:template>
</xsl:stylesheet>
What happened is that the value was taken ONLY on the 1st line item. (1st Name occurence)
The succeeding Name field just copied the value of Nicknames from the 1st Name field.
Kindly advise how to handle the context (loop logic) in the xslt code.
Thanks!
Apologies, but, it seems i did not indicate the complete message structure for the document I am testing.
Order (root)
OrderHeader (1st parent segment)
OrderNumber (child fields - 1st)
Order.. (child fields - 2nd)
Order...(child fields - 2nd)
OrderDetail (1st parent segment)
<fields under this segment were already mentioned from previous threads>
OrderSummary (1st parent segment)
NumOfLines (child fields - 1st)
TotalAmount (child fields - 1st)
Under Order, there are also OrderHeader and OrderSummary parent segment, other than OrderDetail, in which we focus our code.
I've tried your code, but, the segments OrderHeader and OrderSummary and child fields under it were not appearing on my output.
But it seems, I've already generated the correct code.
Here it is,
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" media-type="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
<xsl:template match="/Order/OrderDetail/ListOfItemDetail/ItemDetail/BaseItemDetail/ItemIdentifiers/PartNumbers/BuyerPartNumber">
<xsl:for-each select=".">
<BuyerPartNumber>
<PartNum>
<PartID>
<xsl:value-of select="../ManufacturerPartNumber/PartID"/>
</PartID>
</PartNum>
</BuyerPartNumber>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
I believe, the code you've suggested last time will accomodate only OrderDetail parent segment. Is this correct?
Thanks!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I've added that in my current code, but seems the output still the same. The value in PartID under BuyerPartNumber was just copied to its succeeding ItemDetail fields.
<?xml version='1.0' encoding='UTF-8' ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" media-type="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
<xsl:template match="BuyerPartNumber/PartNum/PartID">
<PartID>
<xsl:value-of select="/Order/OrderDetail/ListOfItemDetail/ItemDetail[1]/BaseItemDetail/ItemIdentifiers/PartNumbers/ManufacturerPartNumber/PartID"/>
</PartID>
</xsl:template>
</xsl:stylesheet>
Would that be ok if I can attach the source document I am currently testing right now to this thread? Although, I don't know how to attach it.
Kindly advise.
I'm thinking, if I can use for-each code?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Please try the relative xpath statement that I suggested:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" media-type="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="BuyerPartNumber/PartNum/PartID">
<PartID>
<xsl:value-of select="../../../ManufacturerPartNumber/PartID"/>
</PartID>
</xsl:template>
</xsl:stylesheet>
Hello,
I've tried this code,
<?xml version='1.0' encoding='UTF-8' ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="SenderPhysicalDUNS" select="'253066740'"/>
<xsl:output method="xml" version="1.0" media-type="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/Order/OrderHeader/OrderReferences/AccountCode/Reference/RefNum">
<RefNum>
<xsl:value-of select="$SenderPhysicalDUNS"/>
</RefNum>
</xsl:template>
<xsl:template match="BuyerPartNumber/PartNum/PartID">
<PartID>
<xsl:value-of select="/Order/OrderDetail/ListOfItemDetail/ItemDetail/BaseItemDetail/ItemIdentifiers/PartNumbers/ManufacturerPartNumber/PartID"/>
</PartID>
</xsl:template>
</xsl:stylesheet>
But the output is still the same.
Only the 1st Part ID under BuyerPartNumber were copied in the 2nd, 3rd, .. iteration of ItemDetail. :'(
I've tried removing the "/" in the Order/OrderDetail... , but there was no value appearing in the BuyerPartNumber/PartNum/PartID..
Kindly provide your inputs.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
The ".." references the parent node of the current node. http://www.w3schools.com/XPath/xpath_syntax.asp The full xpath will always reference the first occurrence and is equivalent to this statement:
/Order/OrderDetail/ListOfItemDetail/ItemDetail[1]/BaseItemDetail/ItemIdentifiers/PartNumbers/ManufacturerPartNumber/PartID
You need an xpath statement relative to your current context (loop iteration):
<xsl:template match="BuyerPartNumber/PartNum/PartID">
<PartID>
<xsl:value-of select="../../../ManufacturerPartNumber/PartID"/>
</PartID>
</xsl:template>
Yep, you're correct with the structure.
SellerPartNumber / BuyerPartNumber / ManufacturingPartNumber are all on the same level.
BuyerPartNumber/PartNum/PartID --> target
ManufacturingPartNumber/PartID --> The value on this value will be copied to BuyerPartNumber/PartNum/PartID
With regards to your code on the 'value-of select', what does ".../.../PartID" means?
Do I need to indicate there the full path from Order root document?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
This is my real source code,
Order (Root)
- OrderHeader (1parent field)- occur only once
- OrderDetail (1parent field)- occur only once
> ListOfItemDetail- occur only once
>> ItemDetail - occur multiple times
>>> BaseItemDetail
>>>> ItemIdentifiers
>>>>> PartNumbers
>>>>>> SellerPartNumber
>>>>>> BuyerPartNumber
>>>>>>> PartNum
>>>>>>>> PartID
>>>>>> ManufacturingPartNumber
>>>>>> PartID
- OrderSummary(1parent field)- occur only once
> --> this indicates the sub-fields under each segment.
- SellerPartNumber / BuyerPartNumber / ManufacturingPartNumber is on the same level
- ItemDetail can occur multiple times, the rest occur only once
The goal is to transfer the value of PartID under ManufacturingPartNumber field into the field PartID of BuyerPartNumber/PartNum.
Hope you can help. Thanks!
Im still debugging the code also.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
From your post I think your XML structure looks like this (ItemDetail can repeat) :
<Order>
<OrderHeader>header</OrderHeader>
<OrderDetail>
<ListOfItemDetail>
<ItemDetail>
<BaseItemDetail>
<ItemIdentifiers>
<PartNumbers>
<SellerPartNumber>spn1</SellerPartNumber>
<BuyerPartNumber>
<PartNum>
<PartID>bpn1</PartID>
</PartNum>
</BuyerPartNumber>
<ManufacturingPartNumber>mpn1</ManufacturingPartNumber>
<PartID>pn1</PartID>
</PartNumbers>
</ItemIdentifiers>
</BaseItemDetail>
</ItemDetail>
</ListOfItemDetail>
</OrderDetail>
<OrderSummary>ordsum</OrderSummary>
</Order>
If so, then try this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" media-type="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="BuyerPartNumber/PartNum/PartID">
<PartID><xsl:value-of select="../../../PartID"/></PartID>
</xsl:template>
</xsl:stylesheet>
Thanks for this helpful information.
This is in consideration that,
School --> Main Header segment (occur only once)
Name --> sub-segment under School field (occur multiple times)
Nickname --> sub-segments under Name (occur only once)
Desired Name --> sub-segments under Name (occur only once)
Will the code you've provided applies?
Meanwhile, I will debug the code on my side also.
Thanks again,
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
It should, the key is to know your current context and use relative or full xpaths depending on what you need. If your template matches on Name you can access all sub-nodes within Name using a relative xpath. Here's what I assumed your sample structure looks like followed by what the xsl will convert it to:
Source:
<DocRoot>
<OtherStuff>
<a>1</a>
</OtherStuff>
<School>
<Name>
<Nickname>Nickname1</Nickname>
<DesiredName>DesiredName1</DesiredName>
</Name>
<Name>
<Nickname>Nickname2</Nickname>
<DesiredName>DesiredName2</DesiredName>
</Name>
</School>
</DocRoot>
Target:
<DocRoot>
<OtherStuff>
<a>1</a>
</OtherStuff>
<School>
<Name>
<Nickname>DesiredName1</Nickname>
<DesiredName>DesiredName1</DesiredName>
</Name>
<Name>
<Nickname>DesiredName2</Nickname>
<DesiredName>DesiredName2</DesiredName>
</Name>
</School>
</DocRoot>
If you needed something different please post back what you want the results to look like.
Thanks,
-Russ
Apologies, here's the logic for the source document I've mentioned above.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" media-type="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Name/Nickname">
<BuyerPartNumber>
<PartNum>
<PartID>
<xsl:value-of select ="Name/Desired name"/>
</PartID>
</PartNum>
</BuyerPartNumber>
</xsl:template>
</xsl:stylesheet>
I will consider your inputs and retest again. I will inform for any updates,
Thanks for your inputs.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Gerberto,
If your template matches Name/Nickname you cannot access Name/DesiredName the way you have shown. If you give the full path /School/Name/DesiredName you will only get the first occurrence. Try getting the value using a context aware xpath like in the example below. This will copy source to target as-is except for the Name/Nickname field. The Nickname value will be replaced with the value from DesiredName within the same "Name" context.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" media-type="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Name/Nickname">
<Nickname><xsl:value-of select="../DesiredName"/></Nickname>
</xsl:template>
</xsl:stylesheet>
If you want to rebuild the entire "Name" node then set your template to match on Name and access fields within Name as follows:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" media-type="xml" encoding="UTF-8" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Name">
<Name>
<DesiredName><xsl:value-of select="DesiredName"/></DesiredName>
<Nickname><xsl:value-of select="DesiredName"/></Nickname>
</Name>
</xsl:template>
</xsl:stylesheet>
Thanks,
-Russ
instead of copy you have to use copy-of
This XSLT seems not to have anything to do with your source XML.
Maybe you check this page, that helped me a lot:
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
87 | |
10 | |
10 | |
10 | |
7 | |
6 | |
6 | |
5 | |
5 | |
4 |
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.