使用xslt从xpath语句列表中注释xml实例
给定一个xpath语句列表,我想编写一个样式表,它将运行一个xml文档并输出同一个文档,但在每个xpath语句中标识的节点之前插入注释。让我们举个例子。从包含xpath语句的xml实例开始:使用xslt从xpath语句列表中注释xml实例,xslt,xpath,xslt-2.0,Xslt,Xpath,Xslt 2.0,给定一个xpath语句列表,我想编写一个样式表,它将运行一个xml文档并输出同一个文档,但在每个xpath语句中标识的节点之前插入注释。让我们举个例子。从包含xpath语句的xml实例开始: <paths> <xpath location="/root/a" annotate="1"/> <xpath location="/root/a/b" annotate="2"/> </paths> 根据输入: <root> &
<paths>
<xpath location="/root/a" annotate="1"/>
<xpath location="/root/a/b" annotate="2"/>
</paths>
根据输入:
<root>
<a>
<b>B</b>
</a>
<c>C</c>
</root>
B
C
它应产生:
<root>
<!-- 1 -->
<a>
<!-- 2 -->
<b>B</b>
</a>
<c>C</c>
</root>
B
C
我最初的想法是创建一个标识样式表,它接受一个文件列表
参数,调用其上的文档
函数来获取xpath节点列表。然后,它将对照该列表检查输入的每个节点,然后在找到注释节点时插入注释节点,但我认为这可能会非常低效,因为XPath列表越来越大(或者可能不是,告诉我,我使用的是saxon 9)
所以我的问题是:有没有一种有效的方法来做这样的事情?概述:
<paths>
<xpath location="/root/a" annotate="1"/>
<xpath location="/root/a/b" annotate="2"/>
<xpath location="/root/c[@x='123']" annotate="3"/>
</paths>
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/paths">
<xsl:element name="xsl:stylesheet">
<xsl:attribute name="version">1.0</xsl:attribute>
<xsl:element name="xsl:output">
<xsl:attribute name="method">xml</xsl:attribute>
<xsl:attribute name="indent">yes</xsl:attribute>
</xsl:element>
<xsl:call-template name="gen_identity_template"/>
<xsl:apply-templates select="xpath"/>
</xsl:element>
</xsl:template>
<xsl:template name="gen_identity_template">
<xsl:element name="xsl:template">
<xsl:attribute name="match">node()|@*</xsl:attribute>
<xsl:element name="xsl:copy">
<xsl:element name="xsl:apply-templates">
<xsl:attribute name="select">node()|@*</xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:template>
<xsl:template match="xpath">
<xsl:element name="xsl:template">
<xsl:attribute name="match">
<xsl:value-of select="@location"/>
</xsl:attribute>
<xsl:element name="xsl:comment">
<xsl:value-of select="@annotate"/>
</xsl:element>
<xsl:element name="xsl:text">
<xsl:text disable-output-escaping="yes">&#xa;</xsl:text>
</xsl:element>
<xsl:element name="xsl:copy">
<xsl:element name="xsl:apply-templates">
<xsl:attribute name="select">node()|@*</xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
<?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"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/a">
<xsl:comment>1</xsl:comment>
<xsl:text>
</xsl:text>
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/a/b">
<xsl:comment>2</xsl:comment>
<xsl:text>
</xsl:text>
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/c[@x='123']">
<xsl:comment>3</xsl:comment>
<xsl:text>
</xsl:text>
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
<root>
<a>
<b>B</b>
</a>
<c x="123">C</c>
</root>
<?xml version="1.0" encoding="UTF-8"?>
<root>
<!--1-->
<a>
<!--2-->
<b>B</b>
</a>
<!--3-->
<c x="123">C</c>
</root>
编写一个元XSLT转换,将路径
文件作为输入,并生成一个新的XSLT转换作为输出。这个新的XSLT将从根输入XML转换为带注释的副本输出XML
注意事项:
<paths>
<xpath location="/root/a" annotate="1"/>
<xpath location="/root/a/b" annotate="2"/>
<xpath location="/root/c[@x='123']" annotate="3"/>
</paths>
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/paths">
<xsl:element name="xsl:stylesheet">
<xsl:attribute name="version">1.0</xsl:attribute>
<xsl:element name="xsl:output">
<xsl:attribute name="method">xml</xsl:attribute>
<xsl:attribute name="indent">yes</xsl:attribute>
</xsl:element>
<xsl:call-template name="gen_identity_template"/>
<xsl:apply-templates select="xpath"/>
</xsl:element>
</xsl:template>
<xsl:template name="gen_identity_template">
<xsl:element name="xsl:template">
<xsl:attribute name="match">node()|@*</xsl:attribute>
<xsl:element name="xsl:copy">
<xsl:element name="xsl:apply-templates">
<xsl:attribute name="select">node()|@*</xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:template>
<xsl:template match="xpath">
<xsl:element name="xsl:template">
<xsl:attribute name="match">
<xsl:value-of select="@location"/>
</xsl:attribute>
<xsl:element name="xsl:comment">
<xsl:value-of select="@annotate"/>
</xsl:element>
<xsl:element name="xsl:text">
<xsl:text disable-output-escaping="yes">&#xa;</xsl:text>
</xsl:element>
<xsl:element name="xsl:copy">
<xsl:element name="xsl:apply-templates">
<xsl:attribute name="select">node()|@*</xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
<?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"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/a">
<xsl:comment>1</xsl:comment>
<xsl:text>
</xsl:text>
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/a/b">
<xsl:comment>2</xsl:comment>
<xsl:text>
</xsl:text>
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/c[@x='123']">
<xsl:comment>3</xsl:comment>
<xsl:text>
</xsl:text>
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
<root>
<a>
<b>B</b>
</a>
<c x="123">C</c>
</root>
<?xml version="1.0" encoding="UTF-8"?>
<root>
<!--1-->
<a>
<!--2-->
<b>B</b>
</a>
<!--3-->
<c x="123">C</c>
</root>
使用XSLT1.0、2.0或3.0
应该是非常有效的,特别是如果
转换必须在大量输入上运行,或者必须运行
重复,因为它有效地编译为本机XSLT,而不是
而不是使用基于XSLT的解释器重新实现匹配
比必须重建的方法更健壮
在代码中手动创建元素祖先。因为它将路径映射到
template/@match
属性,@match
ing的完整复杂性
可以高效地使用。我已经包括了一个属性值测试
举个例子
<>请务必考虑优雅的XSLT 2和3解决方案
和@MartinHonnen,特别是如果中间的元XSLT文件
对你不起作用。通过利用XSLT 3.0的XPath计算
@MartinHonnen的回答似乎能够提供便利
甚至比这里的template/@match
更健壮的匹配
此输入XML指定XPath和批注:
<paths>
<xpath location="/root/a" annotate="1"/>
<xpath location="/root/a/b" annotate="2"/>
<xpath location="/root/c[@x='123']" annotate="3"/>
</paths>
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/paths">
<xsl:element name="xsl:stylesheet">
<xsl:attribute name="version">1.0</xsl:attribute>
<xsl:element name="xsl:output">
<xsl:attribute name="method">xml</xsl:attribute>
<xsl:attribute name="indent">yes</xsl:attribute>
</xsl:element>
<xsl:call-template name="gen_identity_template"/>
<xsl:apply-templates select="xpath"/>
</xsl:element>
</xsl:template>
<xsl:template name="gen_identity_template">
<xsl:element name="xsl:template">
<xsl:attribute name="match">node()|@*</xsl:attribute>
<xsl:element name="xsl:copy">
<xsl:element name="xsl:apply-templates">
<xsl:attribute name="select">node()|@*</xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:template>
<xsl:template match="xpath">
<xsl:element name="xsl:template">
<xsl:attribute name="match">
<xsl:value-of select="@location"/>
</xsl:attribute>
<xsl:element name="xsl:comment">
<xsl:value-of select="@annotate"/>
</xsl:element>
<xsl:element name="xsl:text">
<xsl:text disable-output-escaping="yes">&#xa;</xsl:text>
</xsl:element>
<xsl:element name="xsl:copy">
<xsl:element name="xsl:apply-templates">
<xsl:attribute name="select">node()|@*</xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
<?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"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/a">
<xsl:comment>1</xsl:comment>
<xsl:text>
</xsl:text>
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/a/b">
<xsl:comment>2</xsl:comment>
<xsl:text>
</xsl:text>
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/c[@x='123']">
<xsl:comment>3</xsl:comment>
<xsl:text>
</xsl:text>
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
<root>
<a>
<b>B</b>
</a>
<c x="123">C</c>
</root>
<?xml version="1.0" encoding="UTF-8"?>
<root>
<!--1-->
<a>
<!--2-->
<b>B</b>
</a>
<!--3-->
<c x="123">C</c>
</root>
当输入此元XSLT转换时:
<paths>
<xpath location="/root/a" annotate="1"/>
<xpath location="/root/a/b" annotate="2"/>
<xpath location="/root/c[@x='123']" annotate="3"/>
</paths>
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/paths">
<xsl:element name="xsl:stylesheet">
<xsl:attribute name="version">1.0</xsl:attribute>
<xsl:element name="xsl:output">
<xsl:attribute name="method">xml</xsl:attribute>
<xsl:attribute name="indent">yes</xsl:attribute>
</xsl:element>
<xsl:call-template name="gen_identity_template"/>
<xsl:apply-templates select="xpath"/>
</xsl:element>
</xsl:template>
<xsl:template name="gen_identity_template">
<xsl:element name="xsl:template">
<xsl:attribute name="match">node()|@*</xsl:attribute>
<xsl:element name="xsl:copy">
<xsl:element name="xsl:apply-templates">
<xsl:attribute name="select">node()|@*</xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:template>
<xsl:template match="xpath">
<xsl:element name="xsl:template">
<xsl:attribute name="match">
<xsl:value-of select="@location"/>
</xsl:attribute>
<xsl:element name="xsl:comment">
<xsl:value-of select="@annotate"/>
</xsl:element>
<xsl:element name="xsl:text">
<xsl:text disable-output-escaping="yes">&#xa;</xsl:text>
</xsl:element>
<xsl:element name="xsl:copy">
<xsl:element name="xsl:apply-templates">
<xsl:attribute name="select">node()|@*</xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
<?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"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/a">
<xsl:comment>1</xsl:comment>
<xsl:text>
</xsl:text>
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/a/b">
<xsl:comment>2</xsl:comment>
<xsl:text>
</xsl:text>
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/c[@x='123']">
<xsl:comment>3</xsl:comment>
<xsl:text>
</xsl:text>
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
<root>
<a>
<b>B</b>
</a>
<c x="123">C</c>
</root>
<?xml version="1.0" encoding="UTF-8"?>
<root>
<!--1-->
<a>
<!--2-->
<b>B</b>
</a>
<!--3-->
<c x="123">C</c>
</root>
1
xml
对
节点()|@*
节点()|@*
&#xa;
节点()|@*
将生成此XSLT转换:
<paths>
<xpath location="/root/a" annotate="1"/>
<xpath location="/root/a/b" annotate="2"/>
<xpath location="/root/c[@x='123']" annotate="3"/>
</paths>
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/paths">
<xsl:element name="xsl:stylesheet">
<xsl:attribute name="version">1.0</xsl:attribute>
<xsl:element name="xsl:output">
<xsl:attribute name="method">xml</xsl:attribute>
<xsl:attribute name="indent">yes</xsl:attribute>
</xsl:element>
<xsl:call-template name="gen_identity_template"/>
<xsl:apply-templates select="xpath"/>
</xsl:element>
</xsl:template>
<xsl:template name="gen_identity_template">
<xsl:element name="xsl:template">
<xsl:attribute name="match">node()|@*</xsl:attribute>
<xsl:element name="xsl:copy">
<xsl:element name="xsl:apply-templates">
<xsl:attribute name="select">node()|@*</xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:template>
<xsl:template match="xpath">
<xsl:element name="xsl:template">
<xsl:attribute name="match">
<xsl:value-of select="@location"/>
</xsl:attribute>
<xsl:element name="xsl:comment">
<xsl:value-of select="@annotate"/>
</xsl:element>
<xsl:element name="xsl:text">
<xsl:text disable-output-escaping="yes">&#xa;</xsl:text>
</xsl:element>
<xsl:element name="xsl:copy">
<xsl:element name="xsl:apply-templates">
<xsl:attribute name="select">node()|@*</xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
<?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"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/a">
<xsl:comment>1</xsl:comment>
<xsl:text>
</xsl:text>
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/a/b">
<xsl:comment>2</xsl:comment>
<xsl:text>
</xsl:text>
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/c[@x='123']">
<xsl:comment>3</xsl:comment>
<xsl:text>
</xsl:text>
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
<root>
<a>
<b>B</b>
</a>
<c x="123">C</c>
</root>
<?xml version="1.0" encoding="UTF-8"?>
<root>
<!--1-->
<a>
<!--2-->
<b>B</b>
</a>
<!--3-->
<c x="123">C</c>
</root>
1.
;
2.
;
3.
;
当提供此输入XML文件时:
<paths>
<xpath location="/root/a" annotate="1"/>
<xpath location="/root/a/b" annotate="2"/>
<xpath location="/root/c[@x='123']" annotate="3"/>
</paths>
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/paths">
<xsl:element name="xsl:stylesheet">
<xsl:attribute name="version">1.0</xsl:attribute>
<xsl:element name="xsl:output">
<xsl:attribute name="method">xml</xsl:attribute>
<xsl:attribute name="indent">yes</xsl:attribute>
</xsl:element>
<xsl:call-template name="gen_identity_template"/>
<xsl:apply-templates select="xpath"/>
</xsl:element>
</xsl:template>
<xsl:template name="gen_identity_template">
<xsl:element name="xsl:template">
<xsl:attribute name="match">node()|@*</xsl:attribute>
<xsl:element name="xsl:copy">
<xsl:element name="xsl:apply-templates">
<xsl:attribute name="select">node()|@*</xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:template>
<xsl:template match="xpath">
<xsl:element name="xsl:template">
<xsl:attribute name="match">
<xsl:value-of select="@location"/>
</xsl:attribute>
<xsl:element name="xsl:comment">
<xsl:value-of select="@annotate"/>
</xsl:element>
<xsl:element name="xsl:text">
<xsl:text disable-output-escaping="yes">&#xa;</xsl:text>
</xsl:element>
<xsl:element name="xsl:copy">
<xsl:element name="xsl:apply-templates">
<xsl:attribute name="select">node()|@*</xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
<?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"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/a">
<xsl:comment>1</xsl:comment>
<xsl:text>
</xsl:text>
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/a/b">
<xsl:comment>2</xsl:comment>
<xsl:text>
</xsl:text>
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/c[@x='123']">
<xsl:comment>3</xsl:comment>
<xsl:text>
</xsl:text>
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
<root>
<a>
<b>B</b>
</a>
<c x="123">C</c>
</root>
<?xml version="1.0" encoding="UTF-8"?>
<root>
<!--1-->
<a>
<!--2-->
<b>B</b>
</a>
<!--3-->
<c x="123">C</c>
</root>
B
C
将生成所需的输出XML文件:
<paths>
<xpath location="/root/a" annotate="1"/>
<xpath location="/root/a/b" annotate="2"/>
<xpath location="/root/c[@x='123']" annotate="3"/>
</paths>
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/paths">
<xsl:element name="xsl:stylesheet">
<xsl:attribute name="version">1.0</xsl:attribute>
<xsl:element name="xsl:output">
<xsl:attribute name="method">xml</xsl:attribute>
<xsl:attribute name="indent">yes</xsl:attribute>
</xsl:element>
<xsl:call-template name="gen_identity_template"/>
<xsl:apply-templates select="xpath"/>
</xsl:element>
</xsl:template>
<xsl:template name="gen_identity_template">
<xsl:element name="xsl:template">
<xsl:attribute name="match">node()|@*</xsl:attribute>
<xsl:element name="xsl:copy">
<xsl:element name="xsl:apply-templates">
<xsl:attribute name="select">node()|@*</xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:template>
<xsl:template match="xpath">
<xsl:element name="xsl:template">
<xsl:attribute name="match">
<xsl:value-of select="@location"/>
</xsl:attribute>
<xsl:element name="xsl:comment">
<xsl:value-of select="@annotate"/>
</xsl:element>
<xsl:element name="xsl:text">
<xsl:text disable-output-escaping="yes">&#xa;</xsl:text>
</xsl:element>
<xsl:element name="xsl:copy">
<xsl:element name="xsl:apply-templates">
<xsl:attribute name="select">node()|@*</xsl:attribute>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
<?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"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/a">
<xsl:comment>1</xsl:comment>
<xsl:text>
</xsl:text>
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/a/b">
<xsl:comment>2</xsl:comment>
<xsl:text>
</xsl:text>
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/root/c[@x='123']">
<xsl:comment>3</xsl:comment>
<xsl:text>
</xsl:text>
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
<root>
<a>
<b>B</b>
</a>
<c x="123">C</c>
</root>
<?xml version="1.0" encoding="UTF-8"?>
<root>
<!--1-->
<a>
<!--2-->
<b>B</b>
</a>
<!--3-->
<c x="123">C</c>
</root>
B
C
我不确定kjhughes关于创建第二个转换的建议是否比您最初的想法更有效。如果路径
XML变大,我确实看到第二次转换的可能性变得巨大
我会这样做的
XML输入
<root>
<a>
<b>B</b>
</a>
<c>C</c>
</root>
<root>
<!--1-->
<a>
<!--2-->
<b>B</b>
</a>
<c>C</c>
</root>
B
C
路径XML(path.XML)
XSLT2.0
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="paths" select="document('paths.xml')"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*" priority="1">
<xsl:variable name="path">
<xsl:for-each select="ancestor-or-self::*">
<xsl:value-of select="concat('/',local-name())"/>
</xsl:for-each>
</xsl:variable>
<xsl:if test="$paths/*/xpath[@location=$path]">
<xsl:comment select="$paths/*/xpath[@location=$path]/@annotate"/>
</xsl:if>
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
XML输出
<root>
<a>
<b>B</b>
</a>
<c>C</c>
</root>
<root>
<!--1-->
<a>
<!--2-->
<b>B</b>
</a>
<c>C</c>
</root>
B
C
假设Saxon 9 PE或EE,也可以使用XSLT 3.0和xsl:evaluate
,如下所示:
<?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"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="xs math map mf"
version="3.0">
<xsl:output indent="yes"/>
<xsl:param name="paths-url" as="xs:string" select="'paths1.xml'"/>
<xsl:param name="paths-doc" as="document-node()" select="doc($paths-url)"/>
<xsl:variable name="main-root" select="/"/>
<xsl:variable
name="mapped-nodes">
<map>
<xsl:for-each select="$paths-doc/paths/xpath">
<xsl:variable name="node" as="node()?" select="mf:evaluate(@location, $main-root)"/>
<xsl:if test="$node">
<entry key="{generate-id($node)}">
<xsl:value-of select="@annotate"/>
</entry>
</xsl:if>
</xsl:for-each>
</map>
</xsl:variable>
<xsl:key name="node-by-id" match="map/entry" use="@key"/>
<xsl:function name="mf:evaluate" as="node()?">
<xsl:param name="path" as="xs:string"/>
<xsl:param name="context" as="node()"/>
<xsl:evaluate xpath="$path" context-item="$context"></xsl:evaluate>
</xsl:function>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* , node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node()[key('node-by-id', generate-id(), $mapped-nodes)]">
<xsl:comment select="key('node-by-id', generate-id(), $mapped-nodes)"/>
<xsl:text> </xsl:text>
<xsl:copy>
<xsl:apply-templates select="@* , node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
以下是最初发布的代码的编辑版本,它使用XSLT 3.0映射功能而不是临时文档来存储动态XPath求值找到的节点的生成id与注释之间的关联:
<?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"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="xs math map mf"
version="3.0">
<xsl:param name="paths-url" as="xs:string" select="'paths1.xml'"/>
<xsl:param name="paths-doc" as="document-node()" select="doc($paths-url)"/>
<xsl:output indent="yes"/>
<xsl:variable
name="mapped-nodes"
as="map(xs:string, xs:string)"
select="map:new(for $path in $paths-doc/paths/xpath, $node in mf:evaluate($path/@location, /) return map:entry(generate-id($node), string($path/@annotate)))"/>
<xsl:function name="mf:evaluate" as="node()?">
<xsl:param name="path" as="xs:string"/>
<xsl:param name="context" as="node()"/>
<xsl:evaluate xpath="$path" context-item="$context"></xsl:evaluate>
</xsl:function>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* , node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node()[map:contains($mapped-nodes, generate-id())]">
<xsl:comment select="$mapped-nodes(generate-id())"/>
<xsl:text> </xsl:text>
<xsl:copy>
<xsl:apply-templates select="@* , node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
作为第一个样式表,它需要运行Saxon9.5PE或EE “接得好,”马丁霍宁说。当我编辑我的答案以展示一个更健壮的匹配示例时,我忽略了更新输入XML。现在修好了。谢谢。我想这可能是我将采用的方法,因为我现在对3.0一点都不熟悉。我尝试过使用saxon:evaluate
函数,我怀疑它与Martin的解决方案大致相同。关于这个解决方案,我还没有找到一种方法来注释作为属性节点的XPath。e、 g.“/root/c/@x”
。这是一个非常不同但很好的解决方案+谢谢,丹尼尔,这或多或少是我想到的。我想接下来的问题与xsl:if
元素中test
谓词的性能有关。它是否可能是除O(n)
以外的任何东西,其中n
是路径数?我对这个问题没有很好的把握。关于这个解决方案,我想到了另一件事。我相信如果你的path.xml
有奇怪的XPath,它会失败。因为