【问题标题】:Nokogiri XSLT transform using multiple source XML files使用多个源 XML 文件的 Nokogiri XSLT 转换
【发布时间】:2016-07-21 13:24:47
【问题描述】:

我想使用 Nokogiri 翻译 XML。我构建了一个 XSL,一切正常。我还在 Intellij 中对其进行了测试。我的数据来自两个 XML 文件。

当我尝试让 Nokogiri 进行转换时,我的问题出现了。我似乎找不到让它解析多个源文件的方法。

这是我在文档中使用的代码:

require 'Nokogiri'

doc1 = Nokogiri::XML(File.read('F:/transcoder/xslt_repo/core_xml.xml',))
xslt = Nokogiri::XSLT(File.read('F:/transcoder/xslt_repo/google.xsl'))

puts xslt.transform(doc1)

我试过了:

require 'Nokogiri'

doc1 = Nokogiri::XML(File.read('F:/transcoder/xslt_repo/core_xml.xml',))
doc2 = Nokogiri::XML(File.read('F:/transcoder/xslt_repo/file_data.xml',))
xslt = Nokogiri::XSLT(File.read('F:/transcoder/xslt_repo/test.xsl'))

puts xslt.transform(doc1,doc2)

但是transform 似乎只接受一个参数,所以目前我只能解析我需要的一半数据:

<?xml version="1.0"?>
<package package_id="LB000001">
  <asset_metadata>
    <series_title>test asset 1</series_title>
    <season_title>Number 1</season_title>
    <episode_title>ET 1</episode_title>
    <episode_number>1</episode_number>
    <license_start_date>21-07-2016</license_start_date>
    <license_end_date>31-07-2016</license_end_date>
    <rating>15</rating>
    <synopsis>This is a test asset</synopsis>
  </asset_metadata>
  <video_file>
    <file_name/>
    <file_size/>
    <check_sum/>
  </video_file>
  <image_1>
    <file_name/>
    <file_size/>
    <check_sum/>
  </image_1>
</package>

我怎样才能让它工作?

编辑:

这是通过 PHP 代码块创建的 core_metadata.xml,数据来自数据库。

<?xml version="1.0" encoding="utf-8"?>
<manifest task_id="00000000373">
  <asset_metadata>
    <material_id>LB111111</material_id>
    <series_title>This is a test</series_title>
    <season_title>This is a test</season_title>
    <season_number>1</season_number>
    <episode_title>that test</episode_title>
    <episode_number>2</episode_number>
    <start_date>23-08-2016</start_date>
    <end_date>31-08-2016</end_date>
    <ratings>15</ratings>
    <synopsis>this is a test</synopsis>
  </asset_metadata>
  <file_info>
    <source_filename>LB111111</source_filename>
    <number_of_segments>2</number_of_segments>
    <segment_1 seg_1_start="00:00:10.000" seg_1_dur="00:01:00.000"/>
    <segment_2 seg_2_start="00:02:00.000" seg_2_dur="00:05:00.000"/>
<conform_profile definition="hd" aspect_ratio="16f16">ffmpeg -i S_PATH/F_NAME.mp4 SEG_CONFORM 2&gt; F:/Transcoder/logs/transcode_logs/LOG_FILE.txt</conform_profile>
<transcode_profile profile_name="xbox" package_type="tar">ffmpeg -f concat -i T_PATH/CONFORM_LIST TRC_PATH/F_NAME.mp4 2&gt; F:/Transcoder/logs/transcode_logs/LOG_FILE.txt</transcode_profile>
    <target_path>F:/profiles/xbox</target_path>
  </file_info>
</manifest>

第二个 XML (file_date.xml) 是 nokogiri 在转码过程中动态创建的:

<?xml version="1.0"?>
<file_data>
  <video_file>
    <file_name>LB111111_xbox_230816114438.mp4</file_name>
    <file_size>141959922</file_size>
    <md5_checksum>bac7670e55c0694059d3742285079cbf</md5_checksum>
  </video_file>
  <image_1>
    <file_name>test</file_name>
    <file_size>test</file_size>
    <md5_checksum>test</md5_checksum>
  </image_1>
</file_data>

我通过将 file_date.xml 硬编码到 XSLT 文件中进行调用,设法解决了这个问题:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
    <package>
        <xsl:attribute name="package_id">
            <xsl:value-of select="manifest/asset_metadata/material_id"/>
        </xsl:attribute>
        <asset_metadata>
            <series_title>
                <xsl:value-of select="manifest/asset_metadata/series_title"/>
            </series_title>
            <season_title>
                <xsl:value-of select="manifest/asset_metadata/season_title"/>
            </season_title>
            <episode_title>
                <xsl:value-of select="manifest/asset_metadata/episode_title"/>
            </episode_title>
            <episode_number>
                <xsl:value-of select="manifest/asset_metadata/episode_number"/>
            </episode_number>
            <license_start_date>
                <xsl:value-of select="manifest/asset_metadata/start_date"/>
            </license_start_date>
            <license_end_date>
                <xsl:value-of select="manifest/asset_metadata/end_date"/>
            </license_end_date>
            <rating>
                <xsl:value-of select="manifest/asset_metadata/ratings"/>
            </rating>
            <synopsis>
                <xsl:value-of select="manifest/asset_metadata/synopsis"/>
            </synopsis>
        </asset_metadata>
        <video_file>
            <file_name>
                <xsl:value-of select="document('file_data.xml')/file_data/video_file/file_name"/>
            </file_name>
            <file_size>
                <xsl:value-of select="document('file_data.xml')/file_data/video_file/file_size"/>
            </file_size>
            <check_sum>
                <xsl:value-of select="document('file_data.xml')/file_data/video_file/md5_checksum"/>
            </check_sum>
        </video_file>
        <image_1>
            <file_name>
                <xsl:value-of select="document('file_data.xml')/file_data/image_1/file_name"/>
            </file_name>
            <file_size>
                <xsl:value-of select="document('file_data.xml')/file_data/image_1/file_size"/>
            </file_size>
            <check_sum>
                <xsl:value-of select="document('file_data.xml')/file_data/image_1/md5_checksum"/>
            </check_sum>
        </image_1>
    </package>
</xsl:template>

然后我使用 Saxon 进行转换:

xslt = "java -jar C:/SaxonHE9-7-0-7J/saxon9he.jar #{temp}core_metadata.xml #{temp}#{profile}.xsl > #{temp}#{file_name}.xml"

system("#{xslt}")

我很想找到一种无需将 file_date.xml 硬编码到 XSLT 中的方法。

【问题讨论】:

  • 你为什么要它一次调用transform来转换多个单独的文档?循环它们并独立完成它们。如果您想将它们视为单个文档,则创建一个包装 XML 文档并将其他文档插入其中,然后对其进行转换。
  • 我假设两个 XML 文档具有相同的根,而您希望先合并两者。两个 XML 文档是否都有 &lt;package package_id="LB000001"&gt; 并且它们的内容不同?您是否尝试将有关视频的数据与有关视频集合的数据合并?请提供file_data.xml 的样本。我怀疑解决方案涉及调用转换两次并构建相关对象。
  • 可以使用Nokogiri::XSLT::Stylesheet的apply_to(document, params = []) 方法。将第二个文档的文件路径作为参数传递。然后,在您的转换中,使用规范中定义的标准 XSLT 函数 document():w3.org/TR/xslt#function-document 以在 xsl:variable 中获取第二个文档的根节点

标签: ruby xml xslt nokogiri


【解决方案1】:

合并 XML 文档并转换

在进行 XLS 转换之前,您必须做一些工作来组合 XML 内容。 @the-Tin-Man 有一个不错的 answer to a similar question in the archives,可以根据您的用例进行调整。

假设我们有以下示例内容:

<!--a.xml-->
<?xml version="1.0"?>
<xml>
  <packages>
    <package>Data here for A</package>
    <package>Another Package</package>  
  </packages>
</xml>
<!--a.xml-->

<!--b.xml-->
<?xml version="1.0"?>
<xml>
  <packages>
    <package>B something something</package>  
  </packages>
</xml>
<!--end b.xml-->

我们要应用以下 XLST 模板:

<!--transform.xslt-->
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="//packages">
  <html>
  <body>
    <h2>Packages</h2>
    <ol>
      <xsl:for-each select="./package">
        <li><xsl:value-of select="text()"/></li>
      </xsl:for-each>
    </ol>
  </body>
  </html>
</xsl:template>
</xsl:stylesheet>
<!--end transform.xslt-->

如果我们有并行的文档结构,比如本例,我们可以将两个 XML 文档的内容合并在一起,然后传递给转换。

require 'Nokogiri'

doc1 = Nokogiri::XML(File.read('./a.xml'))
doc2 = Nokogiri::XML(File.read('./b.xml'))

moved_packages = doc2.search('package')
doc1.at('/descendant::packages[1]').add_child(moved_packages)

xslt = Nokogiri::XSLT(File.read('./transform.xslt'))

puts xslt.transform(doc1)

这将生成以下输出:

<html><body>
<h2>Packages</h2>
<ol>
<li>Data here for A</li>
<li>Another Package</li>
<li>B something something</li>
</ol>
</body></html>

如果您的 XML 文档具有不同的结构,您可能会受益于添加内容的中间 XML 节点集,而不是将文档 2 的内容合并到文档 1 的快捷方式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-07
    • 2012-01-12
    • 1970-01-01
    • 1970-01-01
    • 2019-04-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多