如果可能,我需要编写一个XSL文件来转换类似于
的XML语法<media address="1234 A St.">
<book title="My Book" isbn="1324-1123-1456-1566" />
<book title="Your Book" isbn="1232-1123-1456-1566" />
</media>
成这样的格式
<library>
<information>
<building id="1">
<address>1234 A St.</address>
</building>
</information>
<medialist>
<book_definitions>
<book_definition id="2" />
<book_definition id="3" />
</book_definitions>
<book_metadata>
<metadata id="4">
<isbn>1324-1123-1456-1566</isbn>
<book_definition_id>2</book_definition_id>
</metadata>
<metadata id="5">
<isbn>1232-1123-1456-1566</isbn>
<book_definition_id>3</book_definition_id>
</metadata>
</book_metadata>
<book_instances>
<book_instance id="6">
<book_definition_id>2</book_definition_id>
<book_metadata_id>4</book_metadata_id>
<title>My Book</title>
</book_instance>
<book_instance id="7">
<book_definition_id>2</book_definition_id>
<book_metadata_id>5</book_metadata_id>
<title>Your Book</title>
</book_instance>
</book_instances>
</medialist>
</library>
我意识到目标格式有点复杂,但我无法控制它。
我已成功编写XSL,使用模板模式正确转换大多数XML标记。即
<xsl:template match="/media/book" mode="definitions">
<xsl:template match="/media/book" mode="metadata">
<xsl:template match="/media/book" mode="instance">
但是,我一直在尝试使用&lt; xsl:number&gt;或者其他一些技巧来正确生成id,但收效甚微。
目标格式对id有两个约束:每个id属性,不管&lt; element&gt;,name必须是唯一的。一旦排序,ID必须是顺序的,但它们可以按目标格式的任何顺序出现,即(1,2,3,4,5)和(5,2,3,1,4)都可以接受但是( 1,2,4,5,6)不是。
有没有办法通过XSL实现这一目标?
答案 0 :(得分:1)
在我看来,由于(除了建筑物),你总是为每个不同的“种类”节点为每本书生成一个ID,你可以通过根据公式生成它们来保证唯一和顺序id。如果你有N本书,那么你可以“判决”
book_definition
始终为1+m
(因此从2上升到N + 1)(N+1)+m
(2N+1)+m
如果您在任何地方都遵循此方案,您只需计算相应的交叉引用book_definition_id
等,而无需查找表。
答案 1 :(得分:1)
虽然我刚刚注意到Ian Roberts已经解释过这种方法,但我已经准备为此编写一个XSLT,所以我会发布它 - 无论是否遵循XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="/">
<library>
<xsl:apply-templates />
</library>
</xsl:template>
<xsl:template match="media">
<xsl:variable name="current">
<xsl:number />
</xsl:variable>
<information>
<building>
<xsl:attribute name="id">
<xsl:value-of select="$current" />
</xsl:attribute>
<address>
<xsl:value-of select="@address" />
</address>
</building>
</information>
<medialist>
<book_definitions>
<xsl:apply-templates mode="definition">
<xsl:with-param name="current">
<xsl:value-of select="$current" />
</xsl:with-param>
</xsl:apply-templates>
</book_definitions>
<book_metadata>
<xsl:apply-templates mode="metadata">
<xsl:with-param name="current">
<xsl:value-of select="$current" />
</xsl:with-param>
</xsl:apply-templates>
</book_metadata>
<book_instances>
<xsl:apply-templates mode="instances">
<xsl:with-param name="current">
<xsl:value-of select="$current" />
</xsl:with-param>
</xsl:apply-templates>
</book_instances>
</medialist>
</xsl:template>
<xsl:template match="book" mode="definition">
<xsl:param name="current" />
<book_definition id="{(position() + $current)}" />
</xsl:template>
<xsl:template match="book" mode="metadata">
<xsl:param name="current" />
<metadata id="{(position() + $current + count(parent::media/book))}">
<isbn>
<xsl:value-of select="@isbn" />
</isbn>
<book_definition_id>
<xsl:value-of select="position() + $current" />
</book_definition_id>
</metadata>
</xsl:template>
<xsl:template match="book" mode="instances">
<xsl:param name="current" />
<book_instance id="{(position() + 2*count(parent::media/book) + $current)}">
<book_definition_id>
<xsl:value-of select="position() + $current" />
</book_definition_id>
<book_metadata_id>
<xsl:value-of select="position() + $current + count(parent::media/book)" />
</book_metadata_id>
<title>
<xsl:value-of select="@title" />
</title>
</book_instance>
</xsl:template>
</xsl:transform>
当应用于您的输入时,XML会生成输出
<library>
<information>
<building id="1">
<address>1234 A St.</address>
</building>
</information>
<medialist>
<book_definitions>
<book_definition id="2"/>
<book_definition id="3"/>
</book_definitions>
<book_metadata>
<metadata id="4">
<isbn>1324-1123-1456-1566</isbn>
<book_definition_id>2</book_definition_id>
</metadata>
<metadata id="5">
<isbn>1232-1123-1456-1566</isbn>
<book_definition_id>3</book_definition_id>
</metadata>
</book_metadata>
<book_instances>
<book_instance id="6">
<book_definition_id>2</book_definition_id>
<book_metadata_id>4</book_metadata_id>
<title>My Book</title>
</book_instance>
<book_instance id="7">
<book_definition_id>3</book_definition_id>
<book_metadata_id>5</book_metadata_id>
<title>Your Book</title>
</book_instance>
</book_instances>
</medialist>
</library>
由于不清楚输入XML是否包含多个media
元素 - 例如然后应该从id 8开始的下一个建筑 - 我使用数字作为参数而不是仅添加1.
请注意,此模板不适用于第二个media
元素 - 这只是以id
的值2开头 - 如果实际输入XML包含多个,则必须进行相应调整建筑物/ media
元素
对于图书定义,id是当前图书的位置与参数current
的值的总和:
<book_definition id="{(position() + $current)}" />
元数据ID是当前图书的位置,当前/父级media
元素的所有图书和current
的总和:
<metadata id="{(position() + $current + count(parent::media/book))}">
考虑到以前为元数据生成的ID,图书实例ID是当前图书current
的位置与父media
元素* 2的所有图书的总和:
<book_instance id="{(position() + 2*count(parent::media/book) + $current)}">