英文:
XSLT for wrapping immediate following-siblings of certain condition
问题
以下是您提供的XML的翻译,包括XSLT代码部分:
<root>
<i type="r"/>
<i type="s"/>
<i type="r"/>
<i type="r"/>
<i type="s"/>
<i type="r"/>
<i type="s"/>
</root>
我的目标是将所有 <i type="s">
节点与所有紧随其后的类型为 "r"
的节点(1..n)一起包装起来。
不包装的情况:
- 没有前置
"s"
节点的"r"
节点 - 没有紧随后续
"r"
节点的"s"
节点
预期输出:
<i type="r"/>
<wrap>
<i type="s"/>
<i type="r"/>
<i type="r"/>
</wrap>
<wrap>
<i type="s"/>
<i type="r"/>
</wrap>
<i type="s"/>
我一直在尝试使用以下XSLT代码片段解决问题:
<xsl:for-each select="./i">
<xsl:choose>
<xsl:when test="current()[./@type='r' and count(preceding-sibling::i[@type='s']) = 0]">
<!-- 处理不包装 -->
<xsl:apply-templates select="current()" mode="fill"/>
</xsl:when>
<xsl:when test="current()[./@type='s' and following-sibling::i[@type='s']]">
<!-- 处理不包装 -->
<xsl:apply-templates select="current()" mode="fill"/>
</xsl:when>
<xsl:when test="current()[./@type='r' and count(preceding-sibling::i[@type='s']) > 0]">
<!-- 什么都不做 -->
</xsl:when>
<xsl:when test="current()[./@type='s' and following-sibling::i[1][@type='r']]">
<wrap>
<xsl:apply-templates select="current() | //i[@type='r' and preceding-sibling::i[@type='s']" mode="fill"/>
</wrap>
</xsl:when>
</xsl:choose>
</xsl:for-each>
需要注意的是,后续的模板会处理所有的 <I>
节点。这些模板由于与问题本身无关而被省略了。
英文:
I have the following source XML
<root>
<i type="r"/>
<i type="s"/>
<i type="r"/>
<i type="r"/>
<i type="s"/>
<i type="r"/>
<i type="s"/>
</root>
My goal is to wrap together all <i type="s"> occurrences with all immediate following-siblings (1..n) of type="r".
No wrapping for:
- type="r" nodes w/o preceding type="s" node
- type="s" nodes w/o immediate following type="r" node
Expected output:
<i type="r"/>
<wrap>
<i type="s"/>
<i type="r"/>
<i type="r"/>
</wrap>
<wrap>
<i type="s"/>
<i type="r"/>
</wrap>
<i type="s"/>
I have been trying to resolve the problem with the following XSLT snippet:
<xsl:for-each select="./i">
<xsl:choose>
<xsl:when test="current()[./@type='r' and count(preceding-sibling::i[@type='s']) = 0]">
<!-- Processing w/o wrap -->
<xsl:apply-templates select="current()" mode="fill"/>
</xsl:when>
<xsl:when test="current()[./@type='s' and following-sibling::i[@type='s']]">
<!-- Processing w/o wrap -->
<xsl:apply-templates select="current()" mode="fill"/>
</xsl:when>
<xsl:when test="current()[./@type='r' and count(preceding-sibling::i[@type='s']) > 0]">
<!-- Do nothing -->
</xsl:when>
<xsl:when test="current()[./@type='s' and following-sibling::i[1][@type='r']]">
<wrap>
<xsl:apply-templates select="current() | //i[@type='r' and preceding-sibling::i[@type='s']" mode="fill"/>
</wrap>
</xsl:when>
</xsl:choose>
</xsl:for-each>
I'm constantly failing in defining the right context inside <wrap> </wrap>.
Need to note that subsequent templates are processing all <I> nodes. These templates have been omitted due to being irrelevant to the problem itself.
答案1
得分: 0
考虑以下示例:
XML
<root>
<i type="r">1</i>
<i type="s">2</i>
<i type="r">3</i>
<i type="r">4</i>
<i type="s">5</i>
<i type="r">6</i>
<i type="s">7</i>
</root>
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="r" match="i[@type='r']" use="generate-id(preceding-sibling::i[@type='s'][1])" />
<xsl:template match="/root">
<xsl:copy>
<xsl:copy-of select="key('r', '')"/>
<xsl:for-each select="i[@type='s']">
<xsl:variable name="r" select="key('r', generate-id())" />
<xsl:choose>
<xsl:when test="$r">
<wrap>
<xsl:copy-of select=". | $r"/>
</wrap>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<root>
<i type="r">1</i>
<wrap>
<i type="s">2</i>
<i type="r">3</i>
<i type="r">4</i>
</wrap>
<wrap>
<i type="s">5</i>
<i type="r">6</i>
</wrap>
<i type="s">7</i>
</root>
英文:
Consider the following example:
XML
<root>
<i type="r">1</i>
<i type="s">2</i>
<i type="r">3</i>
<i type="r">4</i>
<i type="s">5</i>
<i type="r">6</i>
<i type="s">7</i>
</root>
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="r" match="i[@type='r']" use="generate-id(preceding-sibling::i[@type='s'][1])" />
<xsl:template match="/root">
<xsl:copy>
<xsl:copy-of select="key('r', '')"/>
<xsl:for-each select="i[@type='s']">
<xsl:variable name="r" select="key('r', generate-id())" />
<xsl:choose>
<xsl:when test="$r">
<wrap>
<xsl:copy-of select=". | $r"/>
</wrap>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Result
<?xml version="1.0" encoding="UTF-8"?>
<root>
<i type="r">1</i>
<wrap>
<i type="s">2</i>
<i type="r">3</i>
<i type="r">4</i>
</wrap>
<wrap>
<i type="s">5</i>
<i type="r">6</i>
</wrap>
<i type="s">7</i>
</root>
答案2
得分: 0
这是一个双键方法。
<xsl:key name="r" match="i[@type = 'r']" use="generate-id(preceding-sibling::i[@type = 's'][1])"/>
<xsl:key name="s" match="i[@type = 's']" use="generate-id(following-sibling::i[@type = 'r'][1])"/>
<xsl:template match="i[@type = 's']">
<xsl:variable name="id" select="generate-id(.)"/>
xsl:choose
<xsl:when test="key('r', $id)">
<xsl:element name="wrap">
<xsl:copy-of select="."/>
<xsl:for-each select="key('r', $id)">
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:element>
</xsl:when>
xsl:otherwise
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="i[@type = 'r']">
<xsl:variable name="id" select="generate-id(.)"/>
<xsl:if test="not(key('s', $id))">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:template>
<xsl:template match="node()">
<xsl:apply-templates select="node()"/>
</xsl:template>
英文:
Here is a two key approach.
<xsl:key name="r" match="i[@type = 'r']" use="generate-id(preceding-sibling::i[@type = 's'][1])"/>
<xsl:key name="s" match="i[@type = 's']" use="generate-id(following-sibling::i[@type = 'r'][1])"/>
<xsl:template match="i[@type = 's']">
<xsl:variable name="id" select="generate-id(.)"/>
<xsl:choose>
<!-- Does this s have following r's?-->
<xsl:when test="key('r', $id)">
<xsl:element name="wrap">
<xsl:copy-of select="."/>
<!-- Output the r's that immedately follow this s. -->
<xsl:for-each select="key('r', $id)">
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="i[@type = 'r']">
<xsl:variable name="id" select="generate-id(.)"/>
<!-- Only output r if it does not have a preceding s. -->
<xsl:if test="not(key('s', $id))">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:template>
<!-- Create a template to walk through the nodes on the document. -->
<xsl:template match="node()">
<xsl:apply-templates select="node()"/>
</xsl:template>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论