开发者

XML to XML - Create Unique IDs and reference them in the same document

I have a source xml that contains the addresses in spot and need to transform into an xml that holds all addresses into a single element and references each one. I am using Saxon 9.1 processor and stylesheet version 1.0. Thank you for helping.

Source Code:

<?xml version="1.0" encoding="utf-8"?>
<ContactDetails xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <AddressDetails StartDate="1992-04-03" Type="Previous">
        <Address>
            <City City="Wien" />
            <Postcode Postcode="LSP-123" />
        </Address>
    </AddressDetails>
    <AddressDetails StartDate="1982-09-19" Type="Current">
        <Address>
            <City City="Toronto" />
            <Postcode Postcode="LKT-947" />
        </Address>
    </AddressDetails>
    <AddressDetails StartDate="1977-05-27" Type="Mailing">
        <Address>
            <City City="Sydney" />
            <Postcode Postcode="OKU-846" />
        </Address>
    </AddressDetails>
</ContactDetails>

Target Code:

<?xml version="1.0" encoding="utf-8"?>
<Application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <ContactDetails>
        <AddressDetails StartDate="1992-04-03" Type="Previous">
            <AddressRef ReferedID="Prev_1" />
        </AddressDetails>
        <AddressDetails StartDate="1982-09-19" Type="Current">
            <AddressRef ReferedID="Curr_2" />
        </AddressDetails>
        <AddressDetails StartDate="1977-05-27" Type="Mailing">
            <AddressRef ReferedID="Mail_3" />
        </AddressDetails>
    </ContactDetails>
    <AddressSegment>
            <Address>
                <ID ID="Prev_1" />
                <City City="Wien" />
                <Postcode Postcode="LSP-123" />
            </Address>
            <Address>
                <ID UniqueID="Curr_2" />
                <City City="Toronto" />
                <Postcode Postcode="LKT-947" />
            </Address>        
            <Address>
                <ID UniqueID="Mail_3" />
                <City City="Sydney" />
                <Postcode Postcode="OKU-846" />
            </Address>        
    </AddressSegment>
</Application>

Have played with key and generate-id as I was trying to Generate the ID's first and copy them in the address. Here is my last trial of the xslt (best result I got was to have the UniqueID's empty so I have no idea how far off this solution is :) )

<?xml version='1.0' ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="ID_key" match="*[@ReferedID]" use="@ReferedID"/>
<xsl:template match="/">
    <Application>
    <ContactDetails>
        <xsl:for-each select="Application/Person/ContactDetails/AddressDetails">
        <AddressDetails>
            <xsl:attribute name="StartDate">
            <xsl:value-of select="@StartDate"/>
            </xsl:attribute>
                        <xsl:attribute name="Type">
                            <xsl:value-of select="@Type" />
            </xsl:attribute>
                <AddressRef>
            <xsl:attribute name="ReferedID">
                <xsl:value-of select="generate-id()"/>
            </xsl:attribute>
            </AddressRef>
        </AddressDetails>
        </xsl:for-each>
    </ContactDetails>
    <AddressSegment>
        <xsl:for-each select="Application/Person/ContactDetails/AddressDetails">
        <Address>
            <ID>
            <xsl:attribute name="UniqueID">
                <xsl:value-of select="Address/ID[generate-id()=generate-id(key('ID_key',@UniqueID))]" />
            </xsl:attribute>
        开发者_StackOverflow    </ID>
            <City>
            <xsl:attribute name="City">
                <xsl:value-of select="Address/City/@City"/>
            </xsl:attribute>
            </City>
                        <Postcode>
                                    <sl:attribute name="Postcode">
                    <xsl:value-of select="Address/Postcode/@Postcode"/>
                    </xsl:attribute>
            </Postcode>
        </Address>
            </xsl:for-each>
     </AddressSegment>
   </Application>
   </xsl:template>
</xsl:stylesheet>


To give you an example of how you could use generate-id and modes, the sample stylesheet

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="1.0">

  <xsl:strip-space elements="*"/>
  <xsl:output indent="yes"/>

  <xsl:template match="ContactDetails">
    <xsl:copy>
      <xsl:copy-of select="@*"/>
      <ContactDetails>
        <xsl:apply-templates select="AddressDetails/Address" mode="det"/>
      </ContactDetails>
      <AddressSegment>
        <xsl:apply-templates select="AddressDetails/Address"/>
      </AddressSegment>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Address" mode="det">
    <AddressDetails StartDate="{../@StartDate}" Type="{../@Type}">
      <AddressRef ReferedID="{generate-id()}"/>
    </AddressDetails>
  </xsl:template>

  <xsl:template match="Address">
    <xsl:copy>
      <xsl:copy-of select="@*"/>
      <ID ID="{generate-id()}"/>
      <xsl:copy-of select="*"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

transforms the input

<?xml version="1.0" encoding="utf-8"?>
<ContactDetails xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <AddressDetails StartDate="1992-04-03" Type="Previous">
        <Address>
            <City City="Wien" />
            <Postcode Postcode="LSP-123" />
        </Address>
    </AddressDetails>
    <AddressDetails StartDate="1982-09-19" Type="Current">
        <Address>
            <City City="Toronto" />
            <Postcode Postcode="LKT-947" />
        </Address>
    </AddressDetails>
    <AddressDetails StartDate="1977-05-27" Type="Mailing">
        <Address>
            <City City="Sydney" />
            <Postcode Postcode="OKU-846" />
        </Address>
    </AddressDetails>
</ContactDetails>

with Saxon 6.5.5 into the output

<ContactDetails xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <ContactDetails>
      <AddressDetails StartDate="1992-04-03" Type="Previous">
         <AddressRef ReferedID="d0e3"/>
      </AddressDetails>
      <AddressDetails StartDate="1982-09-19" Type="Current">
         <AddressRef ReferedID="d0e7"/>
      </AddressDetails>
      <AddressDetails StartDate="1977-05-27" Type="Mailing">
         <AddressRef ReferedID="d0e11"/>
      </AddressDetails>
   </ContactDetails>
   <AddressSegment>
      <Address>
         <ID ID="d0e3"/>
         <City City="Wien"/>
         <Postcode Postcode="LSP-123"/>
      </Address>
      <Address>
         <ID ID="d0e7"/>
         <City City="Toronto"/>
         <Postcode Postcode="LKT-947"/>
      </Address>
      <Address>
         <ID ID="d0e11"/>
         <City City="Sydney"/>
         <Postcode Postcode="OKU-846"/>
      </Address>
   </AddressSegment>
</ContactDetails>


The following stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:strip-space elements="*" />
    <xsl:output indent="yes" />
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
    </xsl:template>
    <xsl:template match="ContactDetails">
        <Application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <ContactDetails>
                <xsl:apply-templates select="AddressDetails" />
            </ContactDetails>
            <AddressSegment>
                <xsl:apply-templates select="AddressDetails/Address"
                    mode="ref" />
            </AddressSegment>
        </Application>
    </xsl:template>
    <xsl:template match="AddressDetails/Address">
        <AddressRef ReferedID="{generate-id()}" />
    </xsl:template>
    <xsl:template match="AddressDetails/Address" mode="ref">
        <xsl:copy>
            <xsl:apply-templates select="@*" />
            <ID ID="{generate-id(../*)}" />
            <xsl:apply-templates select="node()" />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

On this input:

<?xml version="1.0" encoding="utf-8"?>
<ContactDetails xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <AddressDetails StartDate="1992-04-03" Type="Previous">
        <Address>
            <City City="Wien" />
            <Postcode Postcode="LSP-123" />
        </Address>
    </AddressDetails>
    <AddressDetails StartDate="1982-09-19" Type="Current">
        <Address>
            <City City="Toronto" />
            <Postcode Postcode="LKT-947" />
        </Address>
    </AddressDetails>
    <AddressDetails StartDate="1977-05-27" Type="Mailing">
        <Address>
            <City City="Sydney" />
            <Postcode Postcode="OKU-846" />
        </Address>
    </AddressDetails>
</ContactDetails>

Produces the desired result:

<Application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <ContactDetails>
        <AddressDetails StartDate="1992-04-03" Type="Previous">
            <AddressRef ReferedID="d1e3" />
        </AddressDetails>
        <AddressDetails StartDate="1982-09-19" Type="Current">
            <AddressRef ReferedID="d1e7" />
        </AddressDetails>
        <AddressDetails StartDate="1977-05-27" Type="Mailing">
            <AddressRef ReferedID="d1e11" />
        </AddressDetails>
    </ContactDetails>
    <AddressSegment>
        <Address>
            <ID ID="d1e3" />
            <City City="Wien" />
            <Postcode Postcode="LSP-123" />
        </Address>
        <Address>
            <ID ID="d1e7" />
            <City City="Toronto" />
            <Postcode Postcode="LKT-947" />
        </Address>
        <Address>
            <ID ID="d1e11" />
            <City City="Sydney" />
            <Postcode Postcode="OKU-846" />
        </Address>
    </AddressSegment>
</Application>

Note the use of the Identity Transform, the most fundamental transformation.


Create Unique IDs and reference them in the same document

If you need to create unique ID for an element, use thegenerate-id() function. Do note that this function generates a unique identifier for a given element in the input document. Therefore if you call the function on the same element, you'll always obtain the same ID. This is really what you want.

For simplicity, in the following example transform, I've applied the templates to AddressDetails two times, each time with a different mode.

Do note the correct generation and reference of the id in the output by applying the generate-id() function on the AddressDetails node.


<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>

    <xsl:template match="ContactDetails">
        <Application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <ContactDetails>
                <xsl:apply-templates select="AddressDetails" mode="contact"/>
            </ContactDetails>
            <AddressSegment>
                <xsl:apply-templates select="AddressDetails" mode="segment"/>
            </AddressSegment>
        </Application>
    </xsl:template>

    <xsl:template match="AddressDetails" mode="contact">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <AddressRef ReferedID="{generate-id(.)}"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="AddressDetails" mode="segment">
        <Address>
            <ID ID="{generate-id(.)}"/>
            <xsl:copy-of select="Address/*"/>
        </Address>
    </xsl:template>

</xsl:stylesheet>

When applied to the input provided in the question, returns:

<Application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <ContactDetails>
      <AddressDetails StartDate="1992-04-03" Type="Previous">
         <AddressRef ReferedID="d1e3"/>
      </AddressDetails>
      <AddressDetails StartDate="1982-09-19" Type="Current">
         <AddressRef ReferedID="d1e13"/>
      </AddressDetails>
      <AddressDetails StartDate="1977-05-27" Type="Mailing">
         <AddressRef ReferedID="d1e23"/>
      </AddressDetails>
   </ContactDetails>
   <AddressSegment>
      <Address>
         <ID ID="d1e3"/>
         <City City="Wien"/>
         <Postcode Postcode="LSP-123"/>
      </Address>
      <Address>
         <ID ID="d1e13"/>
         <City City="Toronto"/>
         <Postcode Postcode="LKT-947"/>
      </Address>
      <Address>
         <ID ID="d1e23"/>
         <City City="Sydney"/>
         <Postcode Postcode="OKU-846"/>
      </Address>
   </AddressSegment>
</Application>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜