我正在尝试根据一些已定义的XPATH从另一个XML生成XML。
XPATH:
country/name,
country/org_id,
country/lang,
country/currency,
generate_date,
schedule/category/id,
schedule/category/name,
schedule/category/classes/class/id,
schedule/category/classes/class/duration,
schedule/category/classes/class/price,
schedule/category/classes/class/instruction_language
Xpath不包括根节点的名称,它是一个列表。
XML:
<?xml version="1.0" encoding="utf-8" ?>
<ou_schedule>
<country>
<name>Country Name</name>
<org_id>Org ID</org_id>
<lang>language</lang>
<currency>Currency</currency>
</country>
<generate_date>Date</generate_date>
<schedule>
<category>
<id>cat id</id>
<name>Cat name</name>
<classes>
<class>
<id>class id</id>
<duration>class duration</duration>
<price>price</price>
<instruction_language>Test Data</instruction_language>
</class>
<class>
<id>class id</id>
<duration>class duration</duration>
<price>price</price>
<instruction_language>Test Data</instruction_language>
</class>
</classes>
</category>
</schedule>
</ou_schedule>
输出:
<?xml version="1.0" encoding="utf-8"?>
<ou_schedule>
<country.name>country name</country.name>
<country.org_id>org id</country.org_id>
<country.lang>language</country.lang>
<country.currency>currency</country.currency>
<generate_date>date</generate_date>
<schedule.category.name>Cat Name</schedule.category.name>
<schedule.category.id>Cat ID</schedule.category.id>
<schedule.category.classes.class.id>class id</schedule.category.classes.class.id>
<schedule.category.classes.class.duration>class duration</schedule.category.classes.class.duration>
<schedule.category.classes.class.price>price</schedule.category.classes.class.price>
<schedule.category.classes.class.instruction_language>Test Data</schedule.category.classes.class.instruction_language>
<country.name>country name</country.name>
<country.org_id>org id</country.org_id>
<country.lang>language</country.lang>
<country.currency>currency</country.currency>
<generate_date>date</generate_date>
<schedule.category.name>Cat Name</schedule.category.name>
<schedule.category.id>Cat ID</schedule.category.id>
<schedule.category.classes.class.id>class id</schedule.category.classes.class.id>
<schedule.category.classes.class.duration>class duration</schedule.category.classes.class.duration>
<schedule.category.classes.class.price>price</schedule.category.classes.class.price>
<schedule.category.classes.class.instruction_language>Test Data</schedule.category.classes.class.instruction_language>
</ou_schedule>
这里,为了消除歧义,我使用除了根节点之外的祖先命名节点名称,即与XPATH相同,但用/
替换.
。
是否可以使用通用XSLT
?
答案 0 :(得分:2)
是否可以使用某些通用XSLT实现此目的?
如果有两个解决方案:一个用于XSLT 1.0,另一个用于XSLT 2.0,则可能(相当人为地)将它们组合成一个,使用XSLT 2.0条件编译技术,将在“预先排除”之前排除编译时“XSLT 1.0解决方案的模板和声明。另一方面,XSLT 1.0解决方案将以向前兼容模式运行,并且还将为其模板指定更高的优先级(高于XSLT 2.0解决方案模板的优先级),因此不会选择XSLT 2.0解决方案的模板执行时,使用XSLT 1.0处理器运行转换。
可以认为这是一个有趣的练习,并按照Michael Kay“XSLT 2.0和XPath 2.0”一书中的示例,第3章:“样式表结构”,“编写便携式样式表”一节,小节:“条件编译”。示例(在我的版本中)位于第128页。
这是一个简短的XSLT 2.0解决方案(如果省略参数值,则为18行),纯(无扩展函数),不使用显式XSLT条件指令或任何{{1} }。甚至不使用xsl:variable
函数:
tokenize()
解决方案2 :
这里将资源(文件)的URI(文件路径)作为参数传递。该文件包含所有想要的XPath表达式 - 每个表达式都在一个单独的行上。
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pPaths" as="xs:string+" select=
"'country/name',
'country/org_id',
'country/lang',
'country/currency',
'generate_date',
'schedule/category/id',
'schedule/category/name',
'schedule/category/classes/class/id',
'schedule/category/classes/class/duration',
'schedule/category/classes/class/price',
'schedule/category/classes/class/instruction_language'"/>
<xsl:template match="/*">
<xsl:copy><xsl:apply-templates/></xsl:copy>
</xsl:template>
<xsl:template match=
"*/*[string-join((ancestor::*[position() ne last()]| .)/name(), '/') = $pPaths]">
<xsl:element
name="{string-join((ancestor::*[position() ne last()]|.)/name(), '.')}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
解决方案3 :
以前的解决方案都可以进一步优化和简化,如果对于输入XPath表达式,已知它们选择具有单个文本节点子元素的元素(这是原始提供的输入XPath表达式的情况,并提供源XML文档):
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pFilePath" select="'file:///C:/temp/expressions.txt'"/>
<xsl:variable name="vExprs" select="tokenize(unparsed-text($pFilePath), '\r?\n')"/>
<xsl:template match="/*">
<xsl:copy><xsl:apply-templates/></xsl:copy>
</xsl:template>
<xsl:template match=
"*/*[string-join((ancestor::*[position() ne last()]| .)/name(), '/') = $vExprs]">
<xsl:element name=
"{string-join((ancestor::*[position() ne last()]|.)/name(), '.')}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
答案 1 :(得分:0)
我的第一个想法是:有趣的是,在这里我们将获得一个动态构建的XSL转换。但这似乎无法实现,因为dynamic xpath in xslt解释道。
因此,需要第二个想法:您可以将XSL转换视为XPATH表达式列表。从这个意义上讲,您只需要一个XSLT文件,如下所示
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="xml" indent="yes"/>
<!-- the following select-attributes are the set of XPATH expressions
(relative to /ou_schedule/schedule/category/classes/class) -->
<xsl:template name="XPathList">
<category_name>
<xsl:apply-templates select="ancestor::category/name"/>
</category_name>
<category_id>
<xsl:apply-templates select="ancestor::category/id"/>
</category_id>
<id>
<xsl:apply-templates select="id"/>
</id>
<duration>
<xsl:apply-templates select="duration"/>
</duration>
<price>
<xsl:apply-templates select="price"/>
</price>
<instruction_language>
<xsl:apply-templates select="instruction_language"/>
</instruction_language>
</xsl:template>
<!-- Basis -->
<xsl:template match="/">
<ou_schedule>
<xsl:apply-templates select="//class"/>
</ou_schedule>
</xsl:template>
<xsl:template match="class">
<xsl:copy>
<xsl:call-template name="XPathList"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
嗯,人们可以用更紧凑的方式编写这种转换。但我们的目标是转换&#34;拥有一系列XPATH来转换XML&#34;代码。