XSLT 分组和转换
XSLT grouping and transformation
我必须通过将相同的节点分组并将它们放入相同的父节点来转换 XML 文件。
示例文件如下所示:
<cars>
<car>
<seller>A</seller>
<make>Ford</make>
<model>Mondeo</model>
<type>Hatchback</type>
</car>
<car>
<seller>A</seller>
<make>Ford</make>
<model>Mondeo</model>
<type>Sedan</type>
</car>
<car>
<seller>A</seller>
<make>Ford</make>
<model>Mondeo</model>
<type>Station wagon</type>
</car>
<car>
<seller>A</seller>
<make>Citroen</make>
<model>C5</model>
<type>Sedan</type>
</car>
<car>
<seller>A</seller>
<make>Citroen</make>
<model>C4</model>
<type>Hatchback</type>
</car>
<car>
<seller>A</seller>
<make>Citroen</make>
<model>C3</model>
<type>Hatchback</type>
</car>
<car>
<seller>A</seller>
<make>Opel</make>
<model>Corsa</model>
<type>Hatchback</type>
</car>
<car>
<seller>A</seller>
<make>Opel</make>
<model>Vectra</model>
<type>Sedan</type>
</car>
<car>
<seller>A</seller>
<make>Opel</make>
<model>Vectra</model>
<type>Station wagon</type>
</car>
</cars>
此文件可以按不同顺序包含更多品牌、型号和类型,但始终只有一个卖家。我必须让它看起来像这样:
<cars>
<seller>A</seller>
<make name="Ford">
<model name="Mondeo" type="Hatchback"/>
<model name="Mondeo" type="Sedan"/>
<model name="Mondeo" type="Station wagon"/>
</make>
<make name="Citroen">
<model name="C5" type="Sedan"/>
<model name="C4" type="Hatchback"/>
<model name="C3" type="Hatchback"/>
</make>
<make name="Opel">
<model name="Corsa" type="Hatchback"/>
<model name="Vectra" type="Sedan"/>
<model name="Vectra" type="Station wagon"/>
</make>
</cars>
在我尝试通过检查当前模型是否与前一个兄弟模型相同之前,我无法做到这一点是“有弹性的”并且可以为每个品牌的每个模型提供更多类型。
我知道如何将一个汽车节点转换为所需的格式:
<?xml version="1.0" encoding="UTF-8"?>
<localEntry key="CarsXSL" xmlns="http://ws.apache.org/ns/synapse">
<xsl:stylesheet version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:element name="cars">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="cars">
<xsl:element name="seller">
<xsl:value-of select="/cars/car[1]/seller/text()"/>
</xsl:element>
<xsl:element name="make">
<xsl:attribute name="name">
<xsl:value-of select="/cars/car/make/text()"/>
</xsl:attribute>
<xsl:element name="model">
<xsl:attribute name="name">
<xsl:value-of select="/cars/car/make/model/text()"/>
</xsl:attribute>
<xsl:attribute name="type">
<xsl:value-of select="/cars/car/make/model/type/text()"/>
</xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
</localEntry>
但我不知道如何按品牌和型号对其进行分组,然后如何将它们放入相同的父节点中。
有可能吗?
试试这个:(根据@michael-hor257k的建议更新)
<?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="xs"
version="1.0">
<xsl:key name="card" match="car" use="make"/>
<xsl:key name="modeld" match="car" use="model"/>
<xsl:key name="types" match="car" use="concat(make, '_', model)"/>
<xsl:output indent="yes"/>
<xsl:template match="cars">
<xsl:copy>
<xsl:for-each select="car[generate-id() = generate-id(key('card', make)[1])]">
<xsl:copy>
<make name="{make}">
<xsl:for-each select="key('card', make)[generate-id() =
generate-id(key('modeld', model)[1])]">
<model name="{model}">
<xsl:copy-of select="key('types', concat(make, '_', model))/type"/>
</model>
</xsl:for-each>
</make>
</xsl:copy>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
请参阅 https://xsltfiddle.liberty-development.net/6q1S8AD/1
处的转换
针对您更新后的问题
<?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="xs"
version="1.0">
<xsl:key name="card" match="car" use="make"/>
<xsl:key name="types" match="car" use="concat(make, '_', model, '_', type)"/>
<xsl:output indent="yes"/>
<xsl:template match="cars">
<xsl:copy>
<seller>
<xsl:value-of select="//seller[1]"/>
</seller>
<car>
<xsl:for-each select="//car[generate-id() = generate-id(key('card', make)[1])]">
<make name="{make}">
<xsl:for-each select="key('card', make)[generate-id() = generate-id(key('types', concat(make, '_', model, '_', type))[1])]">
<model name="{model}" type="{type}"/>
</xsl:for-each>
</make>
</xsl:for-each>
</car>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
处的转换
我必须通过将相同的节点分组并将它们放入相同的父节点来转换 XML 文件。 示例文件如下所示:
<cars>
<car>
<seller>A</seller>
<make>Ford</make>
<model>Mondeo</model>
<type>Hatchback</type>
</car>
<car>
<seller>A</seller>
<make>Ford</make>
<model>Mondeo</model>
<type>Sedan</type>
</car>
<car>
<seller>A</seller>
<make>Ford</make>
<model>Mondeo</model>
<type>Station wagon</type>
</car>
<car>
<seller>A</seller>
<make>Citroen</make>
<model>C5</model>
<type>Sedan</type>
</car>
<car>
<seller>A</seller>
<make>Citroen</make>
<model>C4</model>
<type>Hatchback</type>
</car>
<car>
<seller>A</seller>
<make>Citroen</make>
<model>C3</model>
<type>Hatchback</type>
</car>
<car>
<seller>A</seller>
<make>Opel</make>
<model>Corsa</model>
<type>Hatchback</type>
</car>
<car>
<seller>A</seller>
<make>Opel</make>
<model>Vectra</model>
<type>Sedan</type>
</car>
<car>
<seller>A</seller>
<make>Opel</make>
<model>Vectra</model>
<type>Station wagon</type>
</car>
</cars>
此文件可以按不同顺序包含更多品牌、型号和类型,但始终只有一个卖家。我必须让它看起来像这样:
<cars>
<seller>A</seller>
<make name="Ford">
<model name="Mondeo" type="Hatchback"/>
<model name="Mondeo" type="Sedan"/>
<model name="Mondeo" type="Station wagon"/>
</make>
<make name="Citroen">
<model name="C5" type="Sedan"/>
<model name="C4" type="Hatchback"/>
<model name="C3" type="Hatchback"/>
</make>
<make name="Opel">
<model name="Corsa" type="Hatchback"/>
<model name="Vectra" type="Sedan"/>
<model name="Vectra" type="Station wagon"/>
</make>
</cars>
在我尝试通过检查当前模型是否与前一个兄弟模型相同之前,我无法做到这一点是“有弹性的”并且可以为每个品牌的每个模型提供更多类型。 我知道如何将一个汽车节点转换为所需的格式:
<?xml version="1.0" encoding="UTF-8"?>
<localEntry key="CarsXSL" xmlns="http://ws.apache.org/ns/synapse">
<xsl:stylesheet version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:element name="cars">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="cars">
<xsl:element name="seller">
<xsl:value-of select="/cars/car[1]/seller/text()"/>
</xsl:element>
<xsl:element name="make">
<xsl:attribute name="name">
<xsl:value-of select="/cars/car/make/text()"/>
</xsl:attribute>
<xsl:element name="model">
<xsl:attribute name="name">
<xsl:value-of select="/cars/car/make/model/text()"/>
</xsl:attribute>
<xsl:attribute name="type">
<xsl:value-of select="/cars/car/make/model/type/text()"/>
</xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
</localEntry>
但我不知道如何按品牌和型号对其进行分组,然后如何将它们放入相同的父节点中。 有可能吗?
试试这个:(根据@michael-hor257k的建议更新)
<?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="xs"
version="1.0">
<xsl:key name="card" match="car" use="make"/>
<xsl:key name="modeld" match="car" use="model"/>
<xsl:key name="types" match="car" use="concat(make, '_', model)"/>
<xsl:output indent="yes"/>
<xsl:template match="cars">
<xsl:copy>
<xsl:for-each select="car[generate-id() = generate-id(key('card', make)[1])]">
<xsl:copy>
<make name="{make}">
<xsl:for-each select="key('card', make)[generate-id() =
generate-id(key('modeld', model)[1])]">
<model name="{model}">
<xsl:copy-of select="key('types', concat(make, '_', model))/type"/>
</model>
</xsl:for-each>
</make>
</xsl:copy>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
请参阅 https://xsltfiddle.liberty-development.net/6q1S8AD/1
处的转换针对您更新后的问题
<?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="xs"
version="1.0">
<xsl:key name="card" match="car" use="make"/>
<xsl:key name="types" match="car" use="concat(make, '_', model, '_', type)"/>
<xsl:output indent="yes"/>
<xsl:template match="cars">
<xsl:copy>
<seller>
<xsl:value-of select="//seller[1]"/>
</seller>
<car>
<xsl:for-each select="//car[generate-id() = generate-id(key('card', make)[1])]">
<make name="{make}">
<xsl:for-each select="key('card', make)[generate-id() = generate-id(key('types', concat(make, '_', model, '_', type))[1])]">
<model name="{model}" type="{type}"/>
</xsl:for-each>
</make>
</xsl:for-each>
</car>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
处的转换