Create XML based on 2 XMLs and looking up values in both files using XSLT2.0

穿精又带淫゛_ 提交于 2020-04-30 06:24:49

问题


I am trying to generate a XML based on 2 other XMLs. I am polling a DB that returns details of people(There can be n number of people returned in query). The final XML should have the exact number of Data tags as the distinct name tags in the XML coming from DB. For Ex:

1st XML- Getting this from DB

<parent>
    <child>
        <name>John</name>
        <city>Boston</city>
    </child>
    <child>
        <name>John</name>
        <city>Seattle</city>
    </child>
    <child>
        <name>Allison</name>
        <city>Houston</city>
    </child>
</parent>

2nd XML- Getting this from another source

<details>
    <parent>
        <detail>
            <city>Boston</city>
            <code>abc</code>
        </detail>
        <detail>
            <city>Houston</city>
            <code>xyz</code>
        </detail>
    </parent>
    <parent>
        <detail>
            <city>Boston</city>
            <code>abc</code>
        </detail>
        <detail>
            <city>Seattle</city>
            <code>mno</code>
        </detail>
    </parent>
    <parent>
        <detail>
            <city>Houston</city>
            <code>xyz</code>
        </detail>
        <detail>
            <city>Seattle</city>
            <code>mno</code>
        </detail>
    </parent>
</details>

First I need to create 2 Data Tags as there are 2 distinct names - John and Allison(This part is already done and running fine). Then I need to check for John, whatever unique city tags are present in the DB rows returned. Lets consider the 1st XML, we have John related to Boston and Seattle. So one by one, I will check those cities in the 2nd XML and for every parent tag I match something, I will create a new tag details and paste all the relevant content.

1) If there are no matching entries, details tag should not be created, as there is no matching entry.

2) The city tag is going to come under a parent tag. The values of city tag will be UNIQUE within the parent tag. I have to match the city one by one in 2nd XML and take values from all the matching city tags, across all parents from the 2nd XML and populate in a manner where whatever matched in a parent tag goes in the respective detail tag in output XML. PFB the sample XMLs, that would explain in a better way -

Final Expected XML-

<FinalData>
    <Data>
        <name>John</name>
        <details>
            <detail>
                <city value="Boston">abc</city>
            </detail>
            <detail>
                <city value="Boston">abc</city>
                <city value="Seattle">mno</city>
            </detail>
            <detail>
                <city value="Seattle">mno</city>
            </detail>
        </details>
    </Data>
    <Data>
        <name>Allison</name>
        <details>
            <detail>
                <city value="Houston">xyz</city>
            </detail>
            <detail>
                <city value="Houston">xyz</city>
            </detail>
        </details>
    </Data>
</FinalData>

Currently my XSLT is resulting in someting like below -

<FinalData>
    <Data>
        <name>John</name>
        <details>
            <detail>
                <city value="Boston">abc</city>
                <city value="Boston">abc</city>
                <city value="Seattle">mno</city>
                <city value="Seattle">mno</city>
            </detail>
        </details>
    </Data>
    <Data>
        <name>Allison</name>
        <details>
            <detail>
                <city value="Houston">xyz</city>
                <city value="Houston">xyz</city>
            </detail>
        </details>
    </Data>
</FinalData>

Hope this is clear, as I am not a good at giving explanations.


回答1:


Use keys to resolve the cross-references:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:param name="details">
<details>
    <parent>
        <detail>
            <city>Boston</city>
            <code>abc</code>
        </detail>
        <detail>
            <city>Houston</city>
            <code>xyz</code>
        </detail>
    </parent>
    <parent>
        <detail>
            <city>Boston</city>
            <code>abc</code>
        </detail>
        <detail>
            <city>Seattle</city>
            <code>mno</code>
        </detail>
    </parent>
    <parent>
        <detail>
            <city>Houston</city>
            <code>xyz</code>
        </detail>
        <detail>
            <city>Seattle</city>
            <code>mno</code>
        </detail>
    </parent>
</details>      
  </xsl:param>

  <xsl:key name="parent-ref" match="parent" use="detail/city"/>
  <xsl:key name="detail-ref" match="parent/detail" use="city"/>

  <xsl:output method="xml" indent="yes" />

  <xsl:template match="parent">
    <FinalData>
        <xsl:for-each-group select="child" group-by="name">
            <Data>
                <xsl:copy-of select="name"/>
            </Data>
            <Details>
                <xsl:apply-templates select="key('parent-ref', current-group()/city, $details)"/>
            </Details>
        </xsl:for-each-group>
    </FinalData>
  </xsl:template>

  <xsl:template match="details/parent">
      <detail>
          <xsl:apply-templates select="key('detail-ref', current-group()/city, .)"/>
      </detail>
  </xsl:template>

  <xsl:template match="detail">
      <city value="{city}">
          <xsl:value-of select="code"/>
      </city>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/gVhDDyY

For completeness, the second document is inlined but you can of course use <xsl:param name="details" select="doc('details.xml')"/> instead.



来源:https://stackoverflow.com/questions/61501441/create-xml-based-on-2-xmls-and-looking-up-values-in-both-files-using-xslt2-0

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!