5

所以我正在编写一个 pptx 解析器并使用 OpenXML 来加载数据。一切都很顺利(这是一个谎言——我实际上已经准备好把电脑扔到房间另一边跳出窗户了),但我遇到了加载视频的问题,我根本无法弄清楚。问题是 OpenXML 似乎无法找到指定视频 URI 的关系标签。

我所做的是编写代码来循环浏览幻灯片中的各个部分并注销它们的 ID,如下所示:

SlidePart slidePart = ...;
foreach(var curPart in slidePart.Parts)
  Console.WriteLine("Part ID: " + curPart.RelationshipId);

所以效果很好 - 它会注销 slide.xml.rels 文件中指定的所有关系 - 相关文件的视频关系除外。我可以在rels文件中看到视频关系,它与幻灯片中videoFile标签的链接ID匹配,但我不知道如何通过代码获取它。我的图像加载工作正常(OpenXML 可以找到图像关系)。视频关系的处理方式是否与其他关系不同?如何获取视频 URI?

4

2 回答 2

4

视频关系存储在 SlidePart 的 ExternalReleationships 集合中。

Powerpoint 通过以下方式(简化)将视频(外部文件)嵌入到演示文稿中:

  1. Video它在 ap:timing (class Timing) 标签内为包含视频的幻灯片创建 ap:video (class ) 标签。
  2. p:video 标签包含一个名为 p:cMediaNode (class CommonMediaNode) 的子标签。

  3. p:cMediaNode 包含一个名为 p:tgtEl(类TargetElement)的子节点。

  4. 同样,p:cMediaNode 包含一个名为 p:spTgt (class ShapeTarget) 的子节点,它指向与视频相关的图片形状的 ID。图片形状的ID存储在NonVisualDrawingProperties Id成员中。因此,视频通过这些 Id 连接到图片形状。

  5. 此外,图片形状包含一个名为 a:videoFile (class VideoFromFile) 的子对象。VideoFromFile 类有一个名为的成员Link,它指向外部关系的 Id。

我强烈建议您下载OpenXML SDK 2.0 生产力工具。此工具允许您检查演示文件的生成 XML。

以下代码枚举给定演示文稿中所有幻灯片的所有视频。对于每个视频,都会打印到外部文件的 Uri。这是通过查找给定视频的相关外部关系来完成的。

using (var doc = PresentationDocument.Open("c:\\temp\\presentation.pptx", false))
{
  var presentation = doc.PresentationPart.Presentation;

  foreach (SlideId slideId in presentation.SlideIdList)
  {
    SlidePart slidePart = doc.PresentationPart.GetPartById(slideId.RelationshipId) as SlidePart;
    if (slidePart == null || slidePart.Slide == null)
    {
      continue;
    }

    Slide slide = slidePart.Slide;

    var videos = slide.Descendants<Video>();

    Console.Out.WriteLine("Found videos for slide ID: {0}", slideId.Id);
    foreach (Video video in videos)
    {
      ShapeTarget shapeTarget = video.Descendants<ShapeTarget>().FirstOrDefault();

      Console.Out.WriteLine("ShapeTargetId = {0}", shapeTarget.ShapeId);

      var videoFromFile = slide.CommonSlideData.ShapeTree.Descendants<Picture>().
                Where<Picture>(p => p.NonVisualPictureProperties.Descendants<NonVisualDrawingProperties>().FirstOrDefault().Id == shapeTarget.ShapeId).
                FirstOrDefault().Descendants<VideoFromFile>().FirstOrDefault();                

      Console.Out.WriteLine("Releationship ID: {0}", videoFromFile.Link);

      var externalReleationship = 
                slidePart.ExternalRelationships.Where(er => er.Id == videoFromFile.Link).FirstOrDefault();

      if(externalReleationship == null) // Then it must be embedded
      {
         ReferenceRelationship rr = slidePart.GetReferenceRelationship(videoFromFile.Link);
         if (rr != null)
         {
           Console.Out.WriteLine(rr.Uri.OriginalString);
         }
      }
      else
      {
        Console.Out.WriteLine("Path to video file: {0}", externalReleationship.Uri.AbsolutePath);
      }
    }
  }
}

当然,您也可以直接枚举 a:videoFile (class VideoFromFile) 标签。请参阅下面的代码。

foreach (SlideId slideId in presentation.SlideIdList)
{
  SlidePart slidePart = doc.PresentationPart.GetPartById(slideId.RelationshipId) as SlidePart;
  if (slidePart == null || slidePart.Slide == null)
  {
    continue;
  }

  Slide slide = slidePart.Slide;

  var videos = slide.CommonSlideData.ShapeTree.Descendants<VideoFromFile>();

  foreach (VideoFromFile video in videos)
  {                                
    Console.Out.WriteLine("Releationship ID: {0}", video.Link);

    var externalReleationship =
           slidePart.ExternalRelationships.Where(er => er.Id == video.Link).FirstOrDefault();

    if(externalReleationship == null) 
    {
        ReferenceRelationship rr = slidePart.GetReferenceRelationship(videoFromFile.Link);
        if (rr != null)
        {
          Console.Out.WriteLine(rr.Uri.OriginalString);
        }
    }
    else
    {
      Console.Out.WriteLine("Path to video file: {0}", externalReleationship.Uri.AbsolutePath);
    }
  }
}
于 2012-09-23T10:06:29.987 回答
0

请原谅我重新提出这个早已不复存在的问题,但我刚刚遇到了完全相同的问题,并且我有一个不需要在幻灯片 XML 中挖掘来查找元素的解决方案。事实证明,视频和媒体部分没有出现在slidePart.Parts集合中(如 OP 所述),但它们确实出现在另一个集合slidePart.DataPartReferenceRelationships中。所以我能够找到对嵌入式视频的引用,如下所示:

SlidePart slidePart = ...;
foreach(var videoPart in slidePart.DataPartReferenceRelationships.OfType<VideoReferenceRelationship>())
  Console.WriteLine("Video Part ID: " + videoPart.Id);

对OP有用可能有点晚了,但希望它可以节省一些时间:)

于 2020-05-04T13:53:01.553 回答