【问题标题】:使用基于属性值的 Xslt 转换 Xml 文件
【发布时间】:2022-01-13 17:14:15
【问题描述】:

寻找一种基于预定义值使用 xlst 转换 xml 的方法

我对 xslt 很陌生,如果这是一个基本问题,请原谅我。

输入xml

<?xml version="1.0" encoding="UTF-8"?>
<manifest>

  <project groups="mygroup" name="test1/project1" path="current_dir" />
  <project groups="mygroup" name="test2/project2" path="some_dir/foo"/>
  <project groups="mygroup" name="test3/project3" path="new_dir/bar"/>
  <project groups="mygroup" name="test4/project4" path="current_dir/baz"/>

</manifest>  

寻找输出

<?xml version="1.0" encoding="UTF-8"?>
    <manifest>
    
      <project groups="mygroup" name="test1/project1" path="myfolder" />
      <project groups="mygroup" name="test2/project2" path="myfolder/step1"/>
      <project groups="mygroup" name="test3/project3" path="test_folder/>      
    </manifest>  

基本上,将路径更改为预定义的自定义路径,并排除没有自定义路径的行。

if name="test1/project1" change path="myfolder"
if name="test2/project2" change path="myfolder/step1"
if name="test3/project3" change path="test_folder"

删除其他所有内容

我从下面的代码开始,但这一个修改了相同的路径(考虑到没有条件检查)。 我想添加条件来检查“名称”属性,并将“路径”属性更改为相应的路径,并删除不需要自定义路径的内容。比如上面例子中的test4/project4

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" encoding="utf-8"/>

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
<xsl:template match="/manifest/project/@path">
    <xsl:attribute name="path">Custom Path</xsl:attribute>
</xsl:template>

</xsl:stylesheet>

【问题讨论】:

  • 在询问 XSLT 问题时,您需要提供 minimal reproducible example: (1) 输入 XML。 (2) 你的逻辑,以及试图实现它的 XSLT。 (3) 所需的输出,基于上面#1 中的示例 XML。 (4) XSLT 处理器及其对 XSLT 标准的遵从性:1.0、2.0 或 3.0。
  • 请编辑您的问题并添加样式表在修改path 属性值时应遵循的确切规则。
  • @yitzhak-khabinsky 我坚持匹配确切的属性,如果我有更多关于改进示例的想法,进一步检查会更新问题。
  • 我正在使用 xsltproc 工具进行转换,我认为任何 XSLT 标准都可以工作。
  • @michael.hor257k 添加了一些编辑,是否解决了您的评论?

标签: xml xslt


【解决方案1】:

您发布的规则不清楚。您显示的输出可以使用以下样式表生成 - 但我不确定这是否能提供您问题的真实答案。

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>

<xsl:template match="project">
    <xsl:choose>
        <xsl:when test="@name='test1/project1'">
             <project groups="{@groups}" name="test1/project1" path="myfolder" />
        </xsl:when>
        <xsl:when test="@name='test2/project2'">
             <project groups="{@groups}" name="test2/project2" path="myfolder/step1" />
        </xsl:when>
        <xsl:when test="@name='test3/project3'">
             <project groups="{@groups}" name="test3/project3" path="test_folder" />
        </xsl:when>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>

补充:

是否可以只更改“路径”属性而不重复其他属性?我问这个是因为,随着时间的推移,输入 xml 可能会附加其他属性

不可能“仅更改 path 属性”,因为您还想在没有任何测试返回 true 时完全删除父 project 元素。但是,可以复制所有其他属性:

<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>

<xsl:template match="project">
    <xsl:choose>
        <xsl:when test="@name='test1/project1'">
             <project path="myfolder">
                <xsl:copy-of select="@*[not(name()='path')] "/>
             </project>
        </xsl:when>
        <xsl:when test="@name='test2/project2'">
             <project path="myfolder/step1">
                <xsl:copy-of select="@*[not(name()='path')] "/>
             </project>
        </xsl:when>
        <xsl:when test="@name='test3/project3'">
             <project path="test_folder" >
                <xsl:copy-of select="@*[not(name()='path')] "/>
             </project>
        </xsl:when>
    </xsl:choose>
</xsl:template>

</xsl:stylesheet>

【讨论】:

  • 完美。!!这正是我一直在寻找的。谢谢你。是否可以仅更改“路径”属性而不重复其他属性?我问这个是因为,随着时间的推移,输入 xml 可能会附加其他属性
  • 查看我的答案。
【解决方案2】:

您只需要运行“项目”节点并通过“如果”检查相应的查询,如果有命中则写入更改。

<?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:xsi="http://www.w3.org/2001/XMLSchema-instance" exclude-result-prefixes="#all" version="2.0">
  <xsl:output method="xml" encoding="UTF-8"/>
  <xsl:template match="/">
     <manifest>
          <xsl:for-each select="//manifest/project">
            <xsl:choose>
               <xsl:when test="@name='test1/project1'">
                    <project path="myfolder">
                         <xsl:copy-of select="@*[not(name()='path')]"/>
                    </project>
               </xsl:when>
               <xsl:when test="@name='test2/project2'">
                    <project path="myfolder/step1">
                         <xsl:copy-of select="@*[not(name()='path')]"/>
                    </project>
               </xsl:when>
               <xsl:when test="@name='test3/project3'">
                    <project path="test_folder">
                         <xsl:copy-of select="@*[not(name()='path')]"/>
                    </project>
               </xsl:when>
               <xsl:otherwise>
                    <!-- Otherwise To Nothing -->
               </xsl:otherwise>
            </xsl:choose>
          </xsl:for-each>
     </manifest>
  </xsl:template>
</xsl:stylesheet>

也看看参考:

【讨论】:

  • 谢谢你,@andreas-hauser。是的。该解决方案也有效。正如在我的其他评论中,我没有在问题中说清楚.. 是否可以在匹配后更改“路径”属性并保持该行中的所有其他属性完好无损?将来可能会添加其他属性
  • 当然,因此您只需在 if 条件中获取当前的“项目”节点,并仅更改“路径”属性中的值。
  • 对于互斥替代方案,xsl:choose 优于多个 xsl:if 指令。在找到真实案例后,它会保存多余的评估。
  • @michael.hor257k 你是对的,尤其是当需要处理大量数据时。
猜你喜欢
  • 1970-01-01
  • 2021-12-14
  • 1970-01-01
  • 2012-08-03
  • 1970-01-01
  • 2014-12-21
  • 2010-10-13
  • 2018-06-12
  • 2018-09-22
相关资源
最近更新 更多