从一些已定义的 XPATH 生成 XML
Generate a XML from some defined XPATH
我正在尝试根据一些已定义的 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
来实现此目的?
我的第一个想法是:有趣的是,在这里我们将获得一个动态构建的 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>
好吧,可以用更紧凑的方式编写此转换。但目的是将 "having a list of XPATHs to transform an XML" 的想法转化为代码。
Is it possible to achieve this using some generic XSLT?
如果有两种解决方案:一种用于 XSLT 1.0,另一种用于 XSLT 2.0,则可以(相当人为地)将它们合并为一个,使用 XSLT 2.0 条件编译技术,将排除在 "pre-compile time" XSLT 1.0 解决方案的模板和声明。另一方面,XSLT 1.0 解决方案将在向前兼容模式下运行,并且还将为其模板指定更高的优先级(高于 XSLT 2.0 解决方案模板的优先级),因此没有 XSLT 2.0 解决方案的模板是 selected 执行,当转换 运行 使用 XSLT 1.0 处理器时。
可以将此视为一个有趣的练习,并按照 Michael Kay "XSLT 2.0 and XPath 2.0" 书中的示例,第 3 章:"Stylesheet Structure",第 "Writing Portable stylesheets" 节,小节:"Conditional Compilation"。示例(在我的版本中)在第 128 页。
这是一个简短的 XSLT 2.0 解决方案(如果省略参数值,则为 18 行),纯(无扩展函数),不使用显式 XSLT 条件指令或任何 xsl:variable
。连 tokenize()
函数都没用到:
<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>
解决方案 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="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>
解决方案 3:
如果对于输入的 XPath 表达式已知它们 select 具有单个文本节点子节点的元素(这是最初的情况 -提供了输入 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=
"text()[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>
我正在尝试根据一些已定义的 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
来实现此目的?
我的第一个想法是:有趣的是,在这里我们将获得一个动态构建的 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>
好吧,可以用更紧凑的方式编写此转换。但目的是将 "having a list of XPATHs to transform an XML" 的想法转化为代码。
Is it possible to achieve this using some generic XSLT?
如果有两种解决方案:一种用于 XSLT 1.0,另一种用于 XSLT 2.0,则可以(相当人为地)将它们合并为一个,使用 XSLT 2.0 条件编译技术,将排除在 "pre-compile time" XSLT 1.0 解决方案的模板和声明。另一方面,XSLT 1.0 解决方案将在向前兼容模式下运行,并且还将为其模板指定更高的优先级(高于 XSLT 2.0 解决方案模板的优先级),因此没有 XSLT 2.0 解决方案的模板是 selected 执行,当转换 运行 使用 XSLT 1.0 处理器时。
可以将此视为一个有趣的练习,并按照 Michael Kay "XSLT 2.0 and XPath 2.0" 书中的示例,第 3 章:"Stylesheet Structure",第 "Writing Portable stylesheets" 节,小节:"Conditional Compilation"。示例(在我的版本中)在第 128 页。
这是一个简短的 XSLT 2.0 解决方案(如果省略参数值,则为 18 行),纯(无扩展函数),不使用显式 XSLT 条件指令或任何 xsl:variable
。连 tokenize()
函数都没用到:
<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>
解决方案 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="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>
解决方案 3:
如果对于输入的 XPath 表达式已知它们 select 具有单个文本节点子节点的元素(这是最初的情况 -提供了输入 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=
"text()[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>