在xslt中怎么删除源树中的节点

anhe1364 2016-11-08 10:01:35
我大部分用的是calltemplate来获得自己需要的节点的,有以下问题。
在word中,我用calltemplate对对一个w:r的节点 用value-of进行了处理,我想只使用这个处理之后的结果,但是那个节点本身没有被删除 还会在正文中出现。
请问怎么删除原来的节点啊

或者说怎么再源树上删除变量所对应的节点
...全文
660 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
anhe1364 2016-11-10
  • 打赏
  • 举报
回复
引用 3 楼 rickylin86 的回复:

<?xml version="1.0" encoding="GB2312" standalone="yes"?>
<xsl:stylesheet version="2.0"
				xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
				xmlns:xs="http://www.w3.org/2001/XMLSchema"
				xmlns:myFunc="http://www.ricky.com/function"
				exclude-result-prefixes="xs myFunc">
	<xsl:output indent="yes"/>
	<xsl:template match="/">
		<A>
			<xsl:variable name="es" select="A/*"/>
			<xsl:variable name="startEs" select="A/D[.='start']"/>
			<xsl:variable name="endEs" select="A/D[.='end']"/>
			<xsl:copy-of select="myFunc:format($es,$startEs,$endEs)"/>
		</A>
	</xsl:template>


	<xsl:function name="myFunc:format">
		<xsl:param name="es" as="element(*)*"/>
		<xsl:param name="startEs" as="element(*)*"/>
		<xsl:param name="endEs" as="element(*)*"/>
		<xsl:choose>
			<xsl:when test="count($startEs) ne count($endEs)">
				<!--
				这里用于判断D标签的start和end必须是配对出现的.
				如果不成对出现则直接显示错误信息
				-->
				count-start-elements != count-end-elements.
			</xsl:when>
			<xsl:otherwise>
				<xsl:variable name="end" select="0"/>
				<xsl:for-each select="1 to count($startEs)">
					<xsl:variable name="index" select="."/>
					<xsl:variable name="start" select="myFunc:getIndex($es,$startEs[$index])"/>
					<xsl:variable name="end" select="myFunc:getIndex($es,$endEs[$index])"/>
					<xsl:choose>
						<xsl:when test="$es[xs:integer($start)] is $startEs[1]">
							 <xsl:for-each select="$es[position() >= 1 and position() lt $start]">
								<xsl:copy-of select="."/>
							 </xsl:for-each>
						</xsl:when>
						<xsl:otherwise>
						
							<xsl:variable name="preEndIndex" select="myFunc:getIndex($es,$endEs[xs:integer($index) - 1])"/>
							<xsl:for-each select="$es[position() gt xs:integer($preEndIndex) and position() lt xs:integer($start)]">
								<xsl:copy-of select="."/>
							</xsl:for-each>
						
						</xsl:otherwise>
					</xsl:choose>
					<C>
						<xsl:value-of select="string-join($es[position() gt $start and position() lt $end],'and')"/>
					</C>
				</xsl:for-each>

			</xsl:otherwise>
		</xsl:choose>
	</xsl:function>

	</xsl:stylesheet>
大神,你的写法我看懂了,非常精妙。但是其实我实际面临的问题还要复杂,我在解析word,word论文里面会引用参考文献,每一个段落里面引用参考文献的时候都会出现一个形如

<w:r w:rsidR="00053760">
    <w:rPr>
      <w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman" />
      <w:sz w:val="24" />
    </w:rPr>
    <w:fldChar w:fldCharType="begin" />
  </w:r>
  <w:r w:rsidR="00053760">
    <w:rPr>
      <w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman" />
      <w:sz w:val="24" />
    </w:rPr>
    <w:instrText xml:space="preserve"> REF _Ref466031759 \r \h </w:instrText><!--引用标记-->
  </w:r>
  <w:r w:rsidR="00053760">
    <w:rPr>
      <w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman" />
      <w:sz w:val="24" />
    </w:rPr>
  </w:r>
  <w:r w:rsidR="00053760">
    <w:rPr>
      <w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman" />
      <w:sz w:val="24" />
    </w:rPr>
    <w:fldChar w:fldCharType="separate" />
  </w:r>
  <w:r w:rsidR="00053760">
    <w:rPr>
      <w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman" />
      <w:sz w:val="24" />
    </w:rPr>
    <w:t>[1]</w:t>
  </w:r>
  <w:r w:rsidR="00053760">
    <w:rPr>
      <w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman" />
      <w:sz w:val="24" />
    </w:rPr>
    <w:fldChar w:fldCharType="end" />
  </w:r>
的结构,一开始我是先去寻找 类似<w:instrText xml:space="preserve"> REF _Ref466031759 \r \h </w:instrText>标签,然后根据这个标签,去寻找外面的<w:fldChar w:fldCharType="begin" />标签和 <w:fldChar w:fldCharType="end" />,但是foreach遍历<w:instrText xml:space="preserve"> REF _Ref466031759 \r \h </w:instrText>标签,所得到他两边的begin和end 我又不知道如何放进2个序列中,看了你的写法我深受启发,但是我同时觉得用xslt写这个好复杂,有没有更好的办法呢。 我有一个思路 就是原样输出每一个w:r,但是一旦遇见引用,就把他外面的begin和end包括的内容改造一下,他外面的内容不变输出,不知道您有没有这样的解决方案 另外非常感谢您 给我的答复,非常,非常感谢您
rickylin86 2016-11-10
  • 打赏
  • 举报
回复

可以参考上面的这样的写法
rickylin86 2016-11-10
  • 打赏
  • 举报
回复
可以判断某个节点是否在序列内.主要思路是找出节点在序列中的位置所形成的结果序列. 如果结果序列长度大于0这表示存在. 对应下面的情况可以在XSLT设置node的指针值. 当值1-5时候结果返回true,当大于5时候则为false 数据源:test.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<test>
	<value>1</value>
	<value>2</value>
	<value>3</value>
	<value>4</value>
	<value>5</value>
</test>
对应的XSLT文件:test.xslt

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- 
Parser:Saxon
Command:java net.sf.saxon.Transform -xsl:test.xslt -it:main
-->
<xsl:stylesheet version="2.0" 
				xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
				xmlns:fn="http://www.ricky.com/function"
				xmlns:xs="http://www.w3.org/2001/XMLSchema"
				exclude-result-prefixes="fn xs">
	<xsl:output indent="yes"/>

	<xsl:template name="main">
		<xsl:variable name="source" select="document('test.xml')"/>
		<xsl:variable name="sequence" select="$source/test/*"/><!-- set the value of the sequence -->
		<xsl:variable name="node" select="$source/test/value[2]"/><!-- set the value of the node -->
		<xsl:value-of select="fn:nodeInSequence($sequence,$node)"/>
	</xsl:template>

	<xsl:function name="fn:nodeInSequence" as="xs:boolean">
		<!-- check if the node in the sequence. -->
		<xsl:param name="sequence" as="element(*)*"/>
		<xsl:param name="node" as="element(*)?"/>
		<xsl:variable name="result" as="xs:integer*">
			<xsl:for-each select="$sequence">
				<xsl:if test=". is $node">
					<xsl:value-of select="position()"/>
				</xsl:if>
			</xsl:for-each>
		</xsl:variable>
		<xsl:value-of select="count($result) > 0"/>
	</xsl:function>

</xsl:stylesheet>
rickylin86 2016-11-10
  • 打赏
  • 举报
回复
你在#4楼贴出的数据源其实上处理的方式和#2楼数据源处理上感觉是类似的. 因为XSLT本身就是基于标签的一种语法.所以处理XML源的时候其实有时候会感觉很复杂. 可以考虑学习下XQuery.基本上XQuery能处理XSLT绝大多数需求,另外语法也比较简短紧凑. 我有一个思路 就是原样输出每一个w:r,但是一旦遇见引用,就把他外面的begin和end包括的内容改造一下,他外面的内容不变输出,不知道您有没有这样的解决方案 begin和end处于w:r内部,而且这两个是一个独立的元素.所以第一感觉还是需要用自定义函数来获取起点和结束点进行区域中内容的处理
rickylin86 2016-11-10
  • 打赏
  • 举报
回复
解析器:Saxon - Java

source.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?xml-stylesheet href="test.xslt" type="text/xsl"?>
<A>
<B>B1</B>
<B>B2</B>
<D>start</D>
<B>B3</B>
<B>B4</B>
<D>end</D>
<B>B5</B>
<B>B6</B>
<D>start</D>
<B>B7</B>
<D>end</D>
</A>

对应的xslt文件:test.xslt

<?xml version="1.0" encoding="GB2312" standalone="yes"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:myFunc="http://www.ricky.com/function"
exclude-result-prefixes="xs myFunc">
<xsl:output indent="yes"/>
<xsl:template match="/">
<A>
<xsl:variable name="es" select="A/*"/>
<xsl:variable name="startEs" select="A/D[.='start']"/>
<xsl:variable name="endEs" select="A/D[.='end']"/>
<xsl:copy-of select="myFunc:format($es,$startEs,$endEs)"/>
</A>
</xsl:template>


<xsl:function name="myFunc:format">
<xsl:param name="es" as="element(*)*"/>
<xsl:param name="startEs" as="element(*)*"/>
<xsl:param name="endEs" as="element(*)*"/>
<xsl:choose>
<xsl:when test="count($startEs) ne count($endEs)">
<!--
这里用于判断D标签的start和end必须是配对出现的.
如果不成对出现则直接显示错误信息
-->
count-start-elements != count-end-elements.
</xsl:when>
<xsl:otherwise>
<xsl:variable name="end" select="0"/>
<xsl:for-each select="1 to count($startEs)">
<xsl:variable name="index" select="."/>
<xsl:variable name="start" select="myFunc:getIndex($es,$startEs[$index])"/>
<xsl:variable name="end" select="myFunc:getIndex($es,$endEs[$index])"/>
<xsl:choose>
<xsl:when test="$es[xs:integer($start)] is $startEs[1]">
<xsl:for-each select="$es[position() >= 1 and position() lt $start]">
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>

<xsl:variable name="preEndIndex" select="myFunc:getIndex($es,$endEs[xs:integer($index) - 1])"/>
<xsl:for-each select="$es[position() gt xs:integer($preEndIndex) and position() lt xs:integer($start)]">
<xsl:copy-of select="."/>
</xsl:for-each>

</xsl:otherwise>
</xsl:choose>
<C>
<xsl:value-of select="string-join($es[position() gt $start and position() lt $end],'and')"/>
</C>
</xsl:for-each>

</xsl:otherwise>
</xsl:choose>
</xsl:function>

<xsl:function name="myFunc:getIndex" as="xs:integer">
<!--这个方法用于获取某个节点在序列中的位置指针-->
<xsl:param name="es" as="element(*)*"/>
<xsl:param name="e" as="element(*)"/>
<xsl:for-each select="$es">
<xsl:if test=". is $e">
<xsl:value-of select="position()"/>
</xsl:if>
</xsl:for-each>
</xsl:function>

</xsl:stylesheet>
anhe1364 2016-11-10
  • 打赏
  • 举报
回复
另外一个问题是 有没有函数 可以直接判断一个节点 没有再另外一个节点集合中啊 我有一个变量 <xsl:variable name="comPara_instrTextNull" select="$comPara/w:r[normalize-space(w:instrText)='']"/> 当我foreach comPara里的每一个节点的时候怎么判断节点是不是在变量所代表大集合中呢 我还没找到相关函数
rickylin86 2016-11-09
  • 打赏
  • 举报
回复
源文件test.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?xml-stylesheet href="test.xslt" type="text/xsl"?>
<test>
	<value>
		1
	</value>
	<value>
		2
	</value>
</test>
XSLT文件:test.xslt

<?xml version="1.0" encoding="GB2312" standalone="yes"?>
<xsl:stylesheet version="2.0"
				xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:template match="/">
		<xsl:call-template name="show"/>
		<!-- 
		或许你在运用XSLT的时候添加了类似 apply-templates select="*" 的一个标签内容(如下:A-1)
		导致了会按照默认的方式输出源文档的标签,也就是文本内容
		-->
		<!-- A-1 开始 -->
		<xsl:apply-templates select="test/value"/>
		<!-- A-1 结束 -->

		<!--
		需要解决文本不想出现文本的话可以考虑建立一个对应的模板 如A-2
		可以尝试着注释掉A-2内容看看效果
		-->

	</xsl:template>
	<xsl:template name="show">
		hello,world
	</xsl:template>
	
	<!-- A-2 开始-->
	<xsl:template match="value">
		
	</xsl:template>
	<!-- A-2 结束-->
</xsl:stylesheet>
anhe1364 2016-11-09
  • 打赏
  • 举报
回复
引用 1 楼 rickylin86 的回复:
源文件test.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?xml-stylesheet href="test.xslt" type="text/xsl"?>
<test>
	<value>
		1
	</value>
	<value>
		2
	</value>
</test>
XSLT文件:test.xslt

<?xml version="1.0" encoding="GB2312" standalone="yes"?>
<xsl:stylesheet version="2.0"
				xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
	<xsl:template match="/">
		<xsl:call-template name="show"/>
		<!-- 
		或许你在运用XSLT的时候添加了类似 apply-templates select="*" 的一个标签内容(如下:A-1)
		导致了会按照默认的方式输出源文档的标签,也就是文本内容
		-->
		<!-- A-1 开始 -->
		<xsl:apply-templates select="test/value"/>
		<!-- A-1 结束 -->

		<!--
		需要解决文本不想出现文本的话可以考虑建立一个对应的模板 如A-2
		可以尝试着注释掉A-2内容看看效果
		-->

	</xsl:template>
	<xsl:template name="show">
		hello,world
	</xsl:template>
	
	<!-- A-2 开始-->
	<xsl:template match="value">
		
	</xsl:template>
	<!-- A-2 结束-->
</xsl:stylesheet>
大神 你<xsl:template match="value"></xsl:template>的方法我知道 可是,如果我不是要删除全部的的value呢 例如:
<A>
   <B>B1</B>
   <B>B2</B>
   <D>start</D>
   <B>B3</B>
   <B>B4</B>
   <D>end</D>
   <B>B5</B>
   <B>B6</B>
   <D>start</D>
   <B>B7</B>
   <D>end</D>
</A>
我想将上面的xml换成
<A>
   <B>B1</B>
   <B>B2</B>
   <C>B3和B4</C>
   <B>B5</B>
   <B>B6</B>
   <C>B7</C>
</A>
也就是说将一对<D>start</D> <D>start</D> 之间的内容合并到一个<c></c>标签之中 如果B标签没有在一个D的start节点和一个D的end节点之间 就原样输出。 在你的demo中,template是match所有的value的,而我这里应该是match部分value

8,906

社区成员

发帖
与我相关
我的任务
社区描述
XML/XSL相关问题讨论专区
社区管理员
  • XML/XSL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧