草庐IT

xml - 在给定输入 XML 的情况下,如何使 XSL 产生以下结果

coder 2024-06-27 原文

我已经尝试了几件事...使用变量和模板,但进展缓慢。但我只是没有让它工作 - 我的上下文有问题。

输入...

  • 表“700”可以包含多个条目。
  • Subject1、Subject2、Subject3 的值为 English、Math、Science(但顺序可能因源 XML 而异)
  • 分数与主题有位置关系(即 Score1 用于主题 1)

输出...

  • 将始终包含 6 个节点(ENGLISH、MATH、SCIENCE、Class、Class2、Class3)
  • Subject_ 标签的顺序必须始终是英语、数学,然后是科学。
  • Subject_ 标签将大写
  • 如果相应分数 > 0,则 Subject_ 标签将包含标记 1;否则 0
  • Class_Score 标签的顺序始终需要是英语、数学,然后是科学。

我破坏了我的代码,下面的代码可能无法完全发挥作用,但可以让我了解我的尝试。

我的第一个问题是 - 我走在正确的轨道上吗?

  • 通过 Subject to Grades 模板
  • 捕获主题的“索引”
  • 将主题和索引传递给 add-Grades-nodes 模板

这是我的上下文问题阻止我的地方。

-- 我的输入 XML --

<?xml version="1.0"?>
<Account Number="123456">
  <Data>
    <Table ID="700">
      <Record ID="1" SubClass="Person">
        <Name.Last>Smith</Name.Last>
        <Name.First>John</Name.First>
        <Score1>50</Score1>
        <Score2>75</Score2>
        <Score3>100</Score3>
        <Subject1>Math</Subject1>
        <Subject2>English</Subject2>
        <Subject3>Science</Subject3>
      </Record>
      <Record ID="2" SubClass="Person">
        <Name.Last>Smith</Name.Last>
        <Name.First>Jane</Name.First>
        <Score1></Score1>
        <Score2>77</Score2>
        <Score3>80</Score3>
        <Subject1>Math</Subject1>
        <Subject2>English</Subject2>
        <Subject3>Science</Subject3>
      </Record>
    </Table>
  </Data>
</Account>

-- 期望的输出 XML --

<Out>
    <Subject_ENGLISH>1</Subject_ENGLISH>
    <Subject_MATH>1</Subject_MATH>
    <Subject_SCIENCE>1</Subject_SCIENCE>
    <Class_SCORE>75</Class_SCORE>
    <Class2_SCORE>50</Class2_SCORE>
    <Class3_SCORE>100</Class3_SCORE>
    <Subject_ENGLISH>0</Subject_ENGLISH>
    <Subject_MATH>1</Subject_MATH>
    <Subject_SCIENCE>1</Subject_SCIENCE>
    <Class_SCORE></Class_SCORE>
    <Class2_SCORE>77</Class2_SCORE>
    <Class3_SCORE>80</Class3_SCORE>
</Out>

-- 当前不工作的 XSLT --

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" version="1.0">
  <xsl:output method="xml" encoding="UTF-8"/>

  <xsl:template match="Account">
    <Out>
      <xsl:for-each select="/Account/Data/Table[@ID='700']/Record[@SubClass='Person']>

        <xsl:call-template name="Grades">
          <xsl:with-param name="Subject">English</xsl:with-param>
        </xsl:call-template>
        <xsl:call-template name="Grades">
          <xsl:with-param name="Subject">Math</xsl:with-param>
        </xsl:call-template>
        <xsl:call-template name="Grades">
          <xsl:with-param name="Subject">Science</xsl:with-param>
        </xsl:call-template>


      </xsl:for-each>
    </Out>
  </xsl:template>


  <xsl:template name="Grades">
    <xsl:param name="Subject"/>

    <xsl:for-each select="*[starts-with(name(), 'Subject')][node()=$Subject]">

      <xsl:variable name='cr-index'>
        <xsl:value-of select ='substring(name(), string-length(name()))'/>
      </xsl:variable>

      <xsl:call-template name="create-Grades-nodes">
        <xsl:with-param name="cr-context" select =".."/>
        <xsl:with-param name="Subject">
          <xsl:value-of select='$Subject' />
        </xsl:with-param>
        <xsl:with-param name="cr-index">
          <xsl:value-of select='$cr-index'/>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:for-each>
  </xsl:template>

  <xsl:template name="create-Grades-nodes" match="$cr-context" >
    <xsl:param name ="cr-context"/>
    <xsl:param name ="Subject"/>
    <xsl:param name ="cr-index"/>

    <xsl:variable name='cr-score'>
      <xsl:value-of select='name($cr-context)/concat("Score", $cr-index)'/>
    </xsl:variable>

    <xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'" />
    <xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />

      <xsl:element name='{concat("Subject_", translate($Subject, $smallcase, $uppercase))}'>
        <xsl:choose>
        <xsl:when test= '$cr-score &gt; 0'>
          <xsl:value-of select = "1"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select = "0"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:element>

  </xsl:template>
</xsl:stylesheet>

最佳答案

这个转换:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:param name="pSubjects">
  <s name="English" at="1"/>
  <s name="Math"    at="2"/>
  <s name="Science" at="3"/>
 </xsl:param>

 <xsl:variable name="vSubjects" select=
 "document('')/*/xsl:param[@name='pSubjects']/*"/>

 <xsl:variable name="vLower" select=
  "'abcdefghijklmnopqrstuvwxyz'"/>

 <xsl:variable name="vUpper" select=
  "'ABCDEFGHIJKLMNOPQRSTUVWXYZ'"/>

 <xsl:template match="/*">
  <Out>
   <xsl:apply-templates/>
  </Out>
 </xsl:template>

 <xsl:template match="Table[@ID='700']/Record">
  <xsl:apply-templates select="*[starts-with(name(), 'Su')]">
    <xsl:sort select="$vSubjects[@name = current()]/@at" data-type="number"/>
  </xsl:apply-templates>

  <xsl:apply-templates select="*[starts-with(name(), 'Sc')]">
   <xsl:sort select=
    "$vSubjects[@name
               = current()/../*[starts-with(name(), 'Su')]
                    [substring-after(name(), 'Subject')
                    =
                     substring-after(name(current()), 'Score')
                    ]
                ]/@at"
     data-type="number"/>
  </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="*[starts-with(name(), 'Su')]">
   <xsl:variable name="vgenName" select=
   "concat('Subject_',
            translate(., $vLower, $vUpper)
           )"/>
  <xsl:element name="{$vgenName}">
    <xsl:value-of select="."/>
  </xsl:element>
 </xsl:template>

 <xsl:template match="*[starts-with(name(), 'Sc')]">
  <xsl:variable name="vInd" select=
   "$vSubjects[@name
               = current()/../*[starts-with(name(), 'Su')]
                    [substring-after(name(), 'Subject')
                    =
                     substring-after(name(current()), 'Score')
                    ]
                ]/@at"/>

  <xsl:variable name="vgenName" select=
   "concat('Class',
           translate($vInd, '1', ''),
           '_SCORE'
           )
   "/>
   <xsl:element name="{$vgenName}">
    <xsl:value-of select="."/>
   </xsl:element>
 </xsl:template>
</xsl:stylesheet>

应用于提供的 XML 文档时:

<Account Number="123456">
  <Data>
    <Table ID="700">
      <Record ID="1" SubClass="Person">
        <Name.Last>Smith</Name.Last>
        <Name.First>John</Name.First>
        <Score1>50</Score1>
        <Score2>75</Score2>
        <Score3>100</Score3>
        <Subject1>Math</Subject1>
        <Subject2>English</Subject2>
        <Subject3>Science</Subject3>
      </Record>
      <Record ID="2" SubClass="Person">
        <Name.Last>Smith</Name.Last>
        <Name.First>Jane</Name.First>
        <Score1></Score1>
        <Score2>77</Score2>
        <Score3>80</Score3>
        <Subject1>Math</Subject1>
        <Subject2>English</Subject2>
        <Subject3>Science</Subject3>
      </Record>
    </Table>
  </Data>
</Account>

产生想要的、正确的结果:

<Out>
  <Subject_ENGLISH>English</Subject_ENGLISH>
  <Subject_MATH>Math</Subject_MATH>
  <Subject_SCIENCE>Science</Subject_SCIENCE>
  <Class_SCORE>75</Class_SCORE>
  <Class2_SCORE>50</Class2_SCORE>
  <Class3_SCORE>100</Class3_SCORE>
  <Subject_ENGLISH>English</Subject_ENGLISH>
  <Subject_MATH>Math</Subject_MATH>
  <Subject_SCIENCE>Science</Subject_SCIENCE>
  <Class_SCORE>77</Class_SCORE>
  <Class2_SCORE></Class2_SCORE>
  <Class3_SCORE>80</Class3_SCORE>
</Out>

关于xml - 在给定输入 XML 的情况下,如何使 XSL 产生以下结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8823008/

有关xml - 在给定输入 XML 的情况下,如何使 XSL 产生以下结果的更多相关文章

  1. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  2. ruby - 默认情况下使选项为 false - 2

    这是在Ruby中设置默认值的常用方法:classQuietByDefaultdefinitialize(opts={})@verbose=opts[:verbose]endend这是一个容易落入的陷阱:classVerboseNoMatterWhatdefinitialize(opts={})@verbose=opts[:verbose]||trueendend正确的做法是:classVerboseByDefaultdefinitialize(opts={})@verbose=opts.include?(:verbose)?opts[:verbose]:trueendend编写Verb

  3. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  4. ruby - 在不使用 RVM 的情况下在 Mac 上卸载和升级 Ruby - 2

    我最近决定从我的系统中卸载RVM。在thispage提出的一些论点说服我:实际上,我的决定是,我根本不想担心Ruby的多个版本。我只想使用1.9.2-p290版本而不用担心其他任何事情。但是,当我在我的Mac上运行ruby--version时,它告诉我我的版本是1.8.7。我四处寻找如何简单地从我的Mac上卸载这个Ruby,但奇怪的是我没有找到任何东西。似乎唯一想卸载Ruby的人运行linux,而使用Mac的每个人都推荐RVM。如何从我的Mac上卸载Ruby1.8.7?我想升级到1.9.2-p290版本,并且我希望我的系统上只有一个版本。 最佳答案

  5. ruby - 在什么情况下会使用 Sinatra 或 Merb? - 2

    我正在学习Rails,对Sinatra和Merb知之甚少。我想知道您会在哪些情况下使用Merb/Sinatra。感谢您的反馈! 最佳答案 Sinatra是一个比Rails更小、更轻的框架。如果你想让一些东西快速运行,只需发送几个URL并返回一些简单的内容,就可以使用它。看看Sinatrahomepage;这就是启动和运行“Hello,World”所需的全部内容,而在Rails中,您需要生成整个项目结构、设置Controller和View、设置路由等等(我还没有有一段时间写了一个Rails应用程序,所以我不知道“Hello,World

  6. ruby - 是否可以在不实际发送或读取数据的情况下查明 ruby​​ 套接字是否处于 ESTABLISHED 或 CLOSE_WAIT 状态? - 2

    s=Socket.new(Socket::AF_INET,Socket::SOCK_STREAM,0)s.connect(Socket.pack_sockaddr_in('port','hostname'))ssl=OpenSSL::SSL::SSLSocket.new(s,sslcert)ssl.connect从这里开始,如果ssl连接和底层套接字仍然是ESTABLISHED,或者它是否在默认值7200之后进入CLOSE_WAIT,我想检查一个线程几秒钟甚至更糟的是在实际上不需要.write()或.read()的情况下关闭。是用select()、IO.select()还是其他方法完成

  7. ruby-on-rails - 在这种情况下我如何模拟一个对象?没有明显的方法可以用模拟替换对象 - 2

    假设我在Store的模型中有这个非常简单的方法:defgeocode_addressloc=Store.geocode(address)self.lat=loc.latself.lng=loc.lngend如果我想编写一些不受地理编码服务影响的测试脚本,这些脚本可能已关闭、有限制或取决于我的互联网连接,我该如何模拟地理编码服务?如果我可以将地理编码对象传递到该方法中,那将很容易,但我不知道在这种情况下该怎么做。谢谢!特里斯坦 最佳答案 使用内置模拟和stub的rspecs,你可以做这样的事情:setupdo@subject=MyCl

  8. ruby - 在没有基准或时间的情况下用 Ruby 测量用户时间或系统时间 - 2

    因为我现在正在做一些时间测量,我想知道是否可以在不使用Benchmark类或命令行实用程序time的情况下测量用户时间或系统时间。使用Time类只显示挂钟时间,而不显示系统和用户时间,但是我正在寻找具有相同灵active的解决方案,例如time=TimeUtility.now#somecodeuser,system,real=TimeUtility.now-time原因是我有点不喜欢Benchmark,因为它不能只返回数字(编辑:我错了-它可以。请参阅下面的答案。)。当然,我可以解析输出,但感觉不对。*NIX系统的time实用程序也应该可以解决我的问题,但我想知道是否已经在Ruby中实

  9. ruby - 如何更优雅地记下这三种情况? - 2

    是否可以让这段代码更紧凑?我在这里错过了什么吗?ifvaluemax_ratemax_rateelsevalueend 最佳答案 这里有一些完全不同的东西:[min_rate,value,max_rate].sort[1] 关于ruby-如何更优雅地记下这三种情况?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/13309740/

  10. ruby - 在没有 root 的情况下安装 Jekyll - 2

    我想在共享服务器上建立一个jekyll博客。当我尝试安装Jekyll时,我得到“您没有写权限”。我该如何在没有root或sudo的情况下解决这个问题?更多细节:我在共享服务器上有空间,但没有根访问权限。我无法安装Ruby,尽管托管公司应我的要求安装了它。当我尝试安装Jekyll时我使用user@hosting.org[~]#geminstalljekyll这是我得到的回应:ERROR:Whileexecutinggem...(Gem::FilePermissionError)Youdon'thavewritepermissionsintothe/usr/lib/ruby/gems/1.

随机推荐