1 / 20

Using XSLT and XPath to Transform XML Documents that contain Namespaces

Using XSLT and XPath to Transform XML Documents that contain Namespaces. Roger L. Costello XML Technologies. Problem. Suppose that the document that we are processing is using namespaces:. <?xml version="1.0"?> <?xml-stylesheet type="text/xsl" href="FitnessCenter.xsl"?>

aran
Download Presentation

Using XSLT and XPath to Transform XML Documents that contain Namespaces

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Using XSLT and XPath to Transform XML Documents that contain Namespaces Roger L. Costello XML Technologies

  2. Problem Suppose that the document that we are processing is using namespaces: <?xml version="1.0"?> <?xml-stylesheet type="text/xsl" href="FitnessCenter.xsl"?> <FitnessCenter xmlns="http://www.gym.com"> <Member level="platinum"> <Name>Jeff</Name> <Phone type="home">555-1234</Phone> <Phone type="work">555-4321</Phone> <FavoriteColor>lightgrey</FavoriteColor> </Member> </FitnessCenter> Note that we have a default namespace declaration. Thus, FitnessCenter, Member, Name, Phone, and FavoriteColor all belong to the http://www.gym.com namespace.

  3. <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="html"/> <xsl:template match="/"> <HTML> <BODY> <xsl:apply-templates/> </BODY> </HTML> </xsl:template> <xsl:template match="*"> <xsl:apply-templates/> </xsl:template> <xsl:template match="Member"> Your name is: <xsl:value-of select="Name/text()"/> </xsl:template> <xsl:template match="text()"> <!-- Do nothing --> </xsl:template> </xsl:stylesheet> Output: -- empty -- (see namespaces-example01)

  4. Why is the output empty? <xsl:template match="Member"> Your name is: <xsl:value-of select="Name/text()"/> </xsl:template> This template does not match any element in the instance document! This template matches on a Member element in no namespace. However, in our instance document the Member element is in the http://www.gym.org namespace, i.e., {http://www.gym.com}Member

  5. Namespace Terminology {http://www.gym.com}Member Local name Namespace URI Expanded name = The combination of the namespace URI and the local name

  6. Namespace Terminology (cont.) <gym:FitnessCenter xmlns:gym="http://www.gym.com"> <gym:Member> … </gym:FitnessCenter> <gym:Member> prefix

  7. local-name() • This is a built-in function which returns a string, corresponding to the local name of the element. <xsl:template match="*"> Local name = <xsl:value-of select="local-name(.)"/> <xsl:apply-templates/> </xsl:template> Output: Local name = FitnessCenter Local name = Member Local name = Name Local name = Phone Local name = Phone Local name = FavoriteColor (see namespaces-example02)

  8. <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="html"/> <xsl:template match="/"> <HTML> <BODY> <xsl:apply-templates/> </BODY> </HTML> </xsl:template> <xsl:template match="*"> <xsl:apply-templates/> </xsl:template> <xsl:template match="*[local-name()='Member']"> Your name is: <xsl:value-of select="*[local-name(.)='Name']/text()"/> </xsl:template> <xsl:template match="text()"> <!-- Do nothing --> </xsl:template> </xsl:stylesheet> Output: Your name is: Jeff (see namespaces-example03)

  9. Alternatively <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:gym="http://www.gym.com" version="1.0"> <xsl:output method="html"/> <xsl:template match="/"> <HTML> <BODY> <xsl:apply-templates/> </BODY> </HTML> </xsl:template> <xsl:template match="*"> <xsl:apply-templates/> </xsl:template> <xsl:template match="gym:Member"> Your name is: <xsl:value-of select="gym:Name"/> </xsl:template> <xsl:template match="text()"> <!-- Do nothing --> </xsl:template> </xsl:stylesheet> Declare the gym namespace Match on the Member element in the gym namespace Select the Name element in the gym namespace (see namespaces-example04)

  10. namespace-uri() <xsl:template match="*"> Local name = <xsl:value-of select="local-name(.)"/> Namespace URI = <xsl:value-of select="namespace-uri(.)"/> <xsl:apply-templates/> </xsl:template> • This is a built-in function which returns a string corresponding to the namespace URI of the node. Output: Local name = FitnessCenter Namespace URI = http://www.gym.com Local name = Member Namespace URI = http://www.gym.com Local name = Name Namespace URI = http://www.gym.com Local name = Phone Namespace URI = http://www.gym.com ... (see namespaces-example05)

  11. name() Revisited • We have seen the name() function before. It returns the name of the node. But what name does it return if the node is in a namespace? • Answer: it returns the element name and its prefix (this is called the QName, for Qualified Name)

  12. <?xml version="1.0"?> <?xml-stylesheet type="text/xsl" href="FitnessCenter.xsl"?> <gym:FitnessCenter xmlns:gym="http://www.gym.com"> <gym:Member level="platinum"> <gym:Name>Jeff</gym:Name> <gym:Phone type="home">555-1234</gym:Phone> <gym:Phone type="work">555-4321</gym:Phone> <gym:FavoriteColor>lightgrey</gym:FavoriteColor> </gym:Member> </gym:FitnessCenter> <xsl:template match="*"> Local name = <xsl:value-of select="local-name(.)"/> Namespace URI = <xsl:value-of select="namespace-uri(.)"/> Name = <xsl:value-of select="name(.)"/> <xsl:apply-templates/> </xsl:template>

  13. Output: Local name = FitnessCenter Namespace URI = http://www.gym.com Name = gym:FitnessCenter Local name = Member Namespace URI = http://www.gym.com Name = gym:Member Local name = Name Namespace URI = http://www.gym.com Name = gym:Name Local name = Phone Namespace URI = http://www.gym.com Name = gym:Phone Local name = Phone Namespace URI = http://www.gym.com Name = gym:Phone Local name = FavoriteColor Namespace URI = http://www.gym.com Name = gym:FavoriteColor (see namespaces-example06)

  14. Identity transform - copying namespace declarations • Recall our identity transform stylesheet: <xsl:template match="*"> <xsl:element name="{name(.)}"> <xsl:for-each select="@*"> <xsl:attribute name="{name(.)}"> <xsl:value-of select="."/> </xsl:attribute> </xsl:for-each> <xsl:apply-templates/> </xsl:element> </xsl:template> Iterate through each attribute and add them as attributes onto the element.

  15. @* does not select namespace declarations! • The @* will only select non-namespace declaration attributes. It will not select namespace declaration attributes <Library xmlns="http://www.library.org" xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance" id="Boston Public Library"> This will be selected by @* These will not be selected by @*

  16. Identity transformation for XML documents containing namespaces? • So how do we create a stylesheet that can copy over namespace declarations, along with the other attributes? • Answer: use the <xsl:copy/> element

  17. <xsl:copy/> • This element will copy the current element and all namespace declarations to the output file.

  18. <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml"/> <xsl:template match="* | @*"> <xsl:copy> <xsl:apply-templates select="@*"/> <xsl:apply-templates/> </xsl:copy> </xsl:template> </xsl:stylesheet> (see namespaces-example07) The problem with this identity transform stylesheet is that it's not set up to allow us to make changes to elements/attributes.

  19. <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml"/> <xsl:template match="*"> <xsl:element name="{name(.)}"> <xsl:copy-of select="namespace::*" /> <xsl:for-each select="@*"> <xsl:attribute name="{name(.)}"> <xsl:value-of select="."/> </xsl:attribute> </xsl:for-each> <xsl:apply-templates/> </xsl:element> </xsl:template> </xsl:stylesheet> Error! Attempting to create an element in a namespace, but the namespace has not been declared yet!

  20. <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml"/> <xsl:template match="*"> <xsl:element name="{name(.)}" namespace="{namespace-uri(.)}"> <xsl:copy-of select="namespace::*" /> <xsl:for-each select="@*"> <xsl:attribute name="{name(.)}" namespace="{namespace-uri(.)}"> <xsl:value-of select="."/> </xsl:attribute> </xsl:for-each> <xsl:apply-templates/> </xsl:element> </xsl:template> </xsl:stylesheet> Simultaneously declare the element and its namespace Simultaneously declare the attribute and its namespace (see namespaces-example08)

More Related