如果祖先的属性使用 xsl 持有某个值,我如何删除属性和元素

Posted

技术标签:

【中文标题】如果祖先的属性使用 xsl 持有某个值,我如何删除属性和元素【英文标题】:How do I remove an attribute and an element if an ancestor's attribute holds a certain value using xsl 【发布时间】:2014-12-04 13:52:08 【问题描述】:

我正在努力解决以下问题: 在下面的 XML 中,如果属性嵌套在还包含属性限制 =“限制”的元素中,我需要删除属性限制 =“限制”。如果元素限制嵌套在包含属性限制 =“限制”的元素中,我还需要删除它。但是,如果restrict="restrict" 出现在其祖先不包含属性restrict="restrict" 的嵌套元素上,我需要保留它。限制元素也是如此。如果它没有嵌套在限制元素或没有限制=“限制”属性的元素中,我需要保留它。

<book hasrestrict="yes"> 
<story> <part partno="1"> <parttitle>Title of the Part</parttitle> 
<chapter chapno="11"> <chaptertitle>Title of the Chapter</chaptertitle> 
<section id="id3321234" secno="23">
<sectiontitle>Title of the Section</sectiontitle> 
<toc/> 
<subsection1 restrict="restrict">
<date>(09-23-2012)</date> 
<title>Subsection Title</title> 
<p>Text that makes up the paragraph of the subsetion1. <restrict>This information is  
restricted.</restrict></p> 
<p restrict="restrict">Here is some text in another paragraph that is
restricted. The restrict attribute of the paragraph needs to be
removed because a restrict attribute is already specified for
subsection1. Everything that appears within the element of subsection
1 is already restricted, so I need to remove the unnecessary restrict
attribute from the paragraph because it is causing havoc when my
publishing system tries to format the document.</p>
<subsection2><title>Title of Subsection2</title> 
<p>This is text that appears in a subsecion2 paragraph. 
<list><li>This is an item in a list <restrict>that has restricted content</restrict></li>
<li>Second item</li> 
<li>Third item</li></list></p> 
<subsection3 restrict="restrict">
<title>Title of Subsection3</title> 
<p>Text appearing in a paragraph in subsction 3 
<table frame="all"> <tgroup cols="3" colsep="1" rowsep="1"> 
<colspec colname="col1"/> <colspec colname="col2"/> 
<colspec colname="col3"/>
<thead><row><entry>Entry1</entry>
<entry>Entry2</entry>
<entry>Entry3 <restrict>with restricted information</restrict></entry></row></thead>
<tbody><row><entry restrict="restrict">text</entry>
<entry>text</entry>
<entry>text</entry></row>
</tbody></tgroup></table></p></subsection3></subsection2></subsection1>
<subsection1><date>(09-23-2012)</date> 
<title>Subsection Title</title>
<p>Text that makes up the paragraph of the subsetion1. <restrict>This information is
restricted.</restrict></p> 
<p restrict="restrict">Here is some text in another paragraph that is
restricted. </p> 
<subsection2 restrict="restrict"><title>Title of Subsection2</title>
<p>This is text that appears in a subsecion2 paragraph.</p>
</subsection2></subsection1></section></chapter></part></story></book>

我是 xsl 的新手,曾尝试编写翻译,但运气不佳。

所需的输出应如下所示:

<book hasrestrict="yes">
<story>
<part partno="1">
<parttitle>Title of the Part</parttitle>
<chapter chapno="11">
<chaptertitle>Title of the Chapter</chaptertitle>
<section id="id3321234" secno="23">
<sectiontitle>Title of the Section</sectiontitle>
<toc/>
<subsection1 restrict="restrict"><date>(09-23-2012)</date>
<title>Subsection Title</title>
<p>Text that makes up the paragraph of the subsetion1. This information is restricted.</p>
<p>Here is some text in another paragraph that is restricted. The restrict attribute of the paragraph needs to be removed because a restrict attribute is already specified for subsection1. Everything that appears within the element of subsection1 is already restricted, so I need to remove the unnecessary restrict attribute from the paragraph because it is causing havoc when my publishing system tries to format the document.</p>
<subsection2><title>Title of Subsection2</title>
<p>This is text that appears in a subsecion2 paragraph.
<list>
<li>This is an item in a list that has restricted content</li>
<li>Second item</li>
<li>Third item</li></list></p>
<subsection3><title>Title of Subsection3</title>
<p>Text appearing in a paragraph in subsction 3
<table frame="all">
<tgroup cols="3" colsep="1" rowsep="1">
<colspec colname="col1"/>
<colspec colname="col2"/>
<colspec colname="col3"/>
<thead><row><entry>Entry1</entry>
<entry>Entry2</entry>
<entry>Entry3 with restricted information</entry></row></thead>
<tbody><row>text</entry>
<entry>text</entry>
<entry>text</entry></row></tbody></tgroup></table></p></subsection3></subsection2></subsection1>
<subsection1><date>(09-23-2012)</date>
<title>Subsection Title</title><p>Text that makes up the paragraph of the subsetion1. <restrict>This information is restricted.</restrict></p>
<p restrict="restrict">Here is some text in another paragraph that is restricted. </p>
<subsection2 restrict="restrict"><title>Title of Subsection2</title><p>This is text that appears in a subsecion2 paragraph.</p></subsection2></subsection1></section></chapter></part></story></book>

这是我尝试过的代码:

<xsl:transform version="2.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:template match="@* | node()">
  <xsl:copy>
    <xsl:apply-templates select="@* | node()"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="@restrict">
  <xsl:if test="ancestor::*[@restrict='restrict']">
    <xsl:copy>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:if>
</xsl:template>

<xsl:template match="restrict">
  <xsl:if test="ancestor::*[@restrict='restrict']">
    <xsl:copy>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:if>
</xsl:template>

<xsl:template match="restrict"> 
  <xsl:if test="ancestor::restrict">
    <xsl:copy>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:if>
</xsl:template>     
</xsl:transform>

这对我不起作用。我收到一条错误提示

“警告 org.xml.sax.SAXParseException:从属性节点开始的子轴永远不会选择任何东西”

我真的不知道该怎么做。任何建议(和解释)都会非常有用 赞赏。

【问题讨论】:

这实际上是一个警告,而不是错误——转换仍然成功。警告是让您知道您的 &lt;xsl:copy&gt;&lt;xsl:apply-templates/&gt;&lt;/xsl:copy&gt; 不会做任何事情。您能否详细解释一下当前 XSLT 输出的哪一部分有问题? 我没有达到预期的输出。如果祖先(让我们使用 subsection1)具有限制属性,那么我需要删除每个后代以及第 1 小节中包含的每个限制元素的所有限制属性。但是,如果祖先不包含限制属性,我需要保留后代的限制元素和属性,但我不能将限制元素嵌套在限制元素中。当我运行上面的代码时,什么也没有发生。 【参考方案1】:

当您使用身份模板时,您实际上不需要为您希望保留的元素或属性编写额外的逻辑;不管他们是不是restrict。您只需要为要删除的内容添加模板。

你说“需要删除属性restrict="restrict",如果该属性嵌套在一个还包含属性restrict="restrict"的元素中。那么,执行此操作的模板将像这样:

<xsl:template match="../ancestor::*[@restrict='restrict']]" />

(这里的..是忽略当前具有restrict元素的元素)

对于“如果元素嵌套在包含属性restrict="restrict"的元素中,则删除元素限制。”,模板看起来像这样

<xsl:template match="restrict[ancestor::*[@restrict='restrict']]" /> 

话虽如此,您提到如果restrict 元素没有嵌套在restrict 元素或没有restrict="restrict" 属性的元素中,则保留它们。在这种情况下,模板可能需要如下所示:

<xsl:template match="@restrict[../ancestor::restrict or ../ancestor::*[@restrict='restrict']]" />
<xsl:template match="restrict[ancestor::restrict or ancestor::*[@restrict='restrict']]" /> 

试试这个 XSLT

<xsl:transform version="2.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:template match="@* | node()">
      <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
      </xsl:copy>
    </xsl:template>

    <xsl:template match="@restrict[../ancestor::restrict or ../ancestor::*[@restrict='restrict']]" />        
    <xsl:template match="restrict[ancestor::restrict or ancestor::*[@restrict='restrict']]" /> 
</xsl:transform>

【讨论】:

感谢您的解释和帮助。我真的很感谢你的帮助。这个 XSLT 主要做我想要的,但它从第一个 subsection1 中删除了限制属性,该 subsection1 没有嵌套在限制中。 我已经修改了我的答案来处理这种情况。 我刚刚尝试了修改后的答案,但仍然删除了restrict 属性。这很奇怪,因为祖先没有设置任何限制属性,并且它不包含在限制元素中,那么为什么要剥离它呢? 是否可以编辑您的问题以重新格式化 XML 以使其更具可读性,以便更容易查看属性的位置?我还注意到您的 XSLT 指的是命名空间 (irs)。您的 XML 在现实中是否真的使用命名空间?谢谢! 我现在看到了问题!我已经相应地更新了我的答案【参考方案2】:

如果我理解正确,你想这样做:

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="*"/>

<!-- identity transform -->
<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
</xsl:template>

<!-- remove the attribute restrict="restrict" if the attribute is nested within an element that also contains an attribute restrict="restrict". -->
<xsl:template match="@restrict[.='restrict'][parent::*/ancestor::*/@restrict='restrict']"/>


<!-- remove the element restrict if it is nested within an element containing an attribute restrict="restrict".  -->
<xsl:template match="restrict[ancestor::*/@restrict='restrict']">
    <xsl:apply-templates select="@*|node()"/>
</xsl:template>

</xsl:stylesheet>

【讨论】:

谢谢。这几乎就是我要找的。如果它出现在另一个限制元素中,我还需要删除限制元素。此外,当我对我的 xml 运行此操作时,不会删除嵌套在 p 中的限制元素,该 p 嵌套在具有限制属性的 subsection1 中。 正如我上面提到的,当我使用不同的处理器时,嵌套在 p 中、嵌套在 subsection1 中的具有限制属性的限制元素被删除。感谢您的帮助。 对不起,我并没有真正理解细微差别。不过,我认为您有基础自己进行必要的更改。

以上是关于如果祖先的属性使用 xsl 持有某个值,我如何删除属性和元素的主要内容,如果未能解决你的问题,请参考以下文章

更改XML属性的值会删除其他属性

XSL 在某个字符后显示属性

XSLT祖先元素的不同值

当属性具有'@'时如何在 XSL 中获取值

如何使用 XSL 将 XML 属性值分配给下拉列表

XSL:根据属性计数和匹配创建组