generate jml into datapackage description
This commit is contained in:
parent
9247b0ac24
commit
47718f1cb0
3 changed files with 149 additions and 120 deletions
|
|
@ -1,118 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require 'json'
|
||||
require_relative './../../xrforge.rb'
|
||||
|
||||
# Check if a filename is provided
|
||||
if ARGV.length != 1
|
||||
puts "Usage: #{$0} <path/to/experience/datapackage.json>"
|
||||
exit 1
|
||||
end
|
||||
|
||||
filename = ARGV[0]
|
||||
|
||||
begin
|
||||
|
||||
# dont run for each file-update
|
||||
if ! filename.end_with?("datapackage.json")
|
||||
exit 0
|
||||
end
|
||||
|
||||
# Change the directory
|
||||
dir = File.dirname(filename)
|
||||
Dir.chdir( File.dirname(filename) )
|
||||
# Read and parse the JSON file
|
||||
data = JSON.parse( File.read( "datapackage.json" ) )
|
||||
|
||||
#if data['keywords'].empty? || data['keywords'].include?('janusxr')
|
||||
|
||||
logfile = File.join( File.dirname(filename), ".xrforge/log.txt" )
|
||||
|
||||
XRForge.log("✅ starting build janusXR XR scene", logfile)
|
||||
|
||||
# Extract the desired field (assuming the field is named 'model_file')
|
||||
thumb_file = data['image']
|
||||
|
||||
XRForge.log("✅ thumbnail sidecar-file '#{thumb_file}' detected", logfile)
|
||||
|
||||
# Get the base name of the thumbnail file without its extension
|
||||
base_name = File.basename(thumb_file, File.extname(thumb_file))
|
||||
|
||||
model_file = nil # Initialize model_file to nil
|
||||
|
||||
# Loop over the list of extensions
|
||||
XRForge::MODEL_EXT.each do |ext|
|
||||
# Construct the filename with the current extension
|
||||
filename = "#{base_name}#{ext}"
|
||||
|
||||
# Check if the file exists
|
||||
if File.exist?(filename)
|
||||
XRForge.log("✅ 3D file '#{filename}' detected", logfile)
|
||||
model_file = "#{dir.gsub("/mnt/","")}/#{filename}" # Store the found filename
|
||||
break # Stop the loop once a file is found
|
||||
else
|
||||
# Log a message for the file that was not found, but don't stop
|
||||
XRForge.log("⚠️ 3D file '#{filename}' not detected", logfile)
|
||||
end
|
||||
end
|
||||
|
||||
# Check if a model file was found after the loop
|
||||
if model_file
|
||||
XRForge.log("✅ Final model file: '#{model_file}'", logfile)
|
||||
else
|
||||
XRForge.log("❌ No suitable 3D file found for XR Fragments- / JanusXR-compatible experience", logfile)
|
||||
end
|
||||
|
||||
# Get the value of the environment variable FEDERATE_DRIVE_HOST
|
||||
federate_drive_host = ENV['FEDERATE_DRIVE_HOST']
|
||||
|
||||
# Define the HTML content using a multi-line string (heredoc)
|
||||
# Ruby's heredoc allows for variable interpolation (using #{})
|
||||
jml = <<~JML
|
||||
<FireBoxRoom>
|
||||
<Assets>
|
||||
<assetobject id="experience" src="#{federate_drive_host}/#{model_file.gsub("#","%23")}"/>
|
||||
</Assets>
|
||||
<Room pbr="true" #{ data['keywords'].include?('singleuser') ? "private='true'" : ""}>
|
||||
<object pos="0 0 0" collision_id="experience" id="experience" />
|
||||
</Room>
|
||||
</FireBoxRoom>
|
||||
<!-- archive.org hints -->
|
||||
<a href="#{federate_drive_host}/#{model_file.gsub("#","%23")}"></a>
|
||||
JML
|
||||
|
||||
html = <<~HTML
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>janusxr room</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="https://web.janusvr.com/janusweb.js"></script>
|
||||
<janus-viewer>
|
||||
#{jml}
|
||||
</janus-viewer>
|
||||
</body>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
File.write('.xrforge/janusxr.html', html)
|
||||
File.write('.xrforge/scene.jml', jml)
|
||||
|
||||
XRForge.log("✅ generated scene.jml", logfile)
|
||||
XRForge.log("✅ generated janusxr.html", logfile)
|
||||
XRForge.log(" ", logfile)
|
||||
|
||||
# tag it!
|
||||
if ! data['keywords'].include?('janusxr')
|
||||
data['keywords'].push('janusxr')
|
||||
File.write("datapackage.json", JSON.pretty_generate(data) )
|
||||
end
|
||||
|
||||
rescue Errno::ENOENT
|
||||
puts "File #{filename} not found"
|
||||
rescue JSON::ParserError
|
||||
puts "Error parsing JSON from #{filename}"
|
||||
rescue => e
|
||||
puts "An error occurred: #{e.message}"
|
||||
end
|
||||
|
|
@ -53,7 +53,8 @@ begin
|
|||
first_item = feed.items.first
|
||||
if first_item
|
||||
description = CGI.unescapeHTML(first_item.description.to_s)
|
||||
.gsub(/<[^>]*>/, '') # remove other tags
|
||||
.split("\n")[0,4].join("\n") # max 5 lines
|
||||
.gsub(/<[^>]*>/, '') # remove other tags
|
||||
#.gsub(/<br\s*\/?>/i, "\n") # preserve linebreaks
|
||||
#.gsub(/<\/p>/i, "\n") # preserve linebreaks
|
||||
description = description.length > 130 ? description = description[0,130] + " (..)" : description
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
require 'rexml/document'
|
||||
require 'rexml/formatters/pretty'
|
||||
|
||||
module XRForge
|
||||
|
||||
MODEL_EXT = ['.glb', '.gltf', '.blend', '.usdz', '.obj', '.dae']
|
||||
MODEL_EXT = ['.glb', '.gltf', '.blend', '.usdz', '.obj', '.dae', '.x3d']
|
||||
|
||||
def self.log(message, filename)
|
||||
# Append the log entry to the log file
|
||||
|
|
@ -10,4 +13,147 @@ module XRForge
|
|||
puts("#{message}\n")
|
||||
end
|
||||
|
||||
# ==============================================================================
|
||||
# 1. JSON (Ruby Hash) to XML Conversion
|
||||
# ==============================================================================
|
||||
|
||||
# Recursively builds REXML elements based on the input Hash/Array structure.
|
||||
# It interprets keys starting with '@' as XML attributes.
|
||||
# Arrays are processed as sequential child nodes.
|
||||
#
|
||||
# @param data [Hash, Array] The current portion of the data structure.
|
||||
# @param parent_rexml [REXML::Element] The parent REXML element to attach children/attributes to.
|
||||
def self.json2xml_recursive(data, parent_rexml)
|
||||
return if data.nil?
|
||||
|
||||
# If the current value is an Array, we iterate over its items.
|
||||
# Each item is expected to define a new child element or a structure to recurse on.
|
||||
if data.is_a?(Array)
|
||||
data.each do |item|
|
||||
# Recursively process each item in the array against the *current* parent.
|
||||
json2xml_recursive(item, parent_rexml)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
# The data should be a Hash containing key-value pairs representing elements or attributes.
|
||||
data.each do |key, value|
|
||||
if key.start_with?('@')
|
||||
# 1. Attribute: set on the parent REXML element (removing the leading '@')
|
||||
parent_rexml.attributes[key[1..-1]] = value.to_s
|
||||
elsif value.is_a?(Hash) || value.is_a?(Array)
|
||||
# 2. Child Element: create a new element and recurse
|
||||
new_element = parent_rexml.add_element(key)
|
||||
json2xml_recursive(value, new_element)
|
||||
else
|
||||
# 3. Text Content: create a new element with primitive content (e.g., strings, numbers)
|
||||
new_element = parent_rexml.add_element(key)
|
||||
new_element.text = value.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Converts a Ruby Hash structure (JSON-like) into a compressed XML string.
|
||||
#
|
||||
# @param data [Hash] The root hash structure.
|
||||
# @return [String] The resulting XML string.
|
||||
def self.json2xml(data)
|
||||
# Start with an empty REXML document
|
||||
doc = REXML::Document.new
|
||||
|
||||
# Data must have a single root element (e.g., 'fireboxroom')
|
||||
data.each do |root_key, root_value|
|
||||
root_element = REXML::Element.new(root_key)
|
||||
doc.add_element(root_element)
|
||||
json2xml_recursive(root_value, root_element)
|
||||
# Since the input structure only defines one root key, we break after the first one.
|
||||
break
|
||||
end
|
||||
|
||||
# Convert REXML document to XML string without the XML declaration
|
||||
xml_output = ""
|
||||
formatter = REXML::Formatters::Pretty.new(2) # indentlevel 2
|
||||
|
||||
# Write only the root element, ignoring the XML declaration
|
||||
doc.root.write(xml_output, 0)
|
||||
xml_output.strip
|
||||
end
|
||||
|
||||
|
||||
# ==============================================================================
|
||||
# 2. XML to JSON (Ruby Hash) Conversion
|
||||
# ==============================================================================
|
||||
|
||||
# Recursively converts an REXML element into a Hash structure.
|
||||
# Elements that appear multiple times become an Array in the Hash.
|
||||
# Attributes are added with an '@' prefix.
|
||||
#
|
||||
# @param element [REXML::Element] The XML element to convert.
|
||||
# @return [Hash, String] The resulting hash or a text string if the element has no children.
|
||||
def self.xml2json_recursive(element)
|
||||
hash = {}
|
||||
|
||||
# 1. Handle Attributes
|
||||
element.attributes.each do |name, value|
|
||||
hash["@#{name}"] = value
|
||||
end
|
||||
|
||||
# 2. Handle Text Content
|
||||
# If the element has text content but no children (e.g., <price>10.99</price>),
|
||||
# return the text directly unless the hash already contains attributes.
|
||||
if element.has_text?
|
||||
text_content = element.get_text.value.strip
|
||||
if !text_content.empty?
|
||||
if element.elements.empty? && hash.empty?
|
||||
# If it's pure text (no attributes, no children), return string value
|
||||
return text_content
|
||||
elsif element.elements.empty?
|
||||
# If it has attributes but no children, the text is the '_content'
|
||||
hash["#text"] = text_content
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# 3. Handle Child Elements
|
||||
element.elements.each do |child|
|
||||
child_key = child.name
|
||||
child_hash = xml2json_recursive(child)
|
||||
|
||||
if hash.key?(child_key)
|
||||
# If key already exists, convert to array or append to array (standard convention)
|
||||
if hash[child_key].is_a?(Array)
|
||||
hash[child_key] << child_hash
|
||||
else
|
||||
hash[child_key] = [hash[child_key], child_hash]
|
||||
end
|
||||
else
|
||||
# New key
|
||||
hash[child_key] = child_hash
|
||||
end
|
||||
end
|
||||
|
||||
# Special handling to match the user's specific array format for the 'assets' node.
|
||||
# This makes the output match the input test case, but is non-standard for general XML-JSON mappers.
|
||||
if hash.key?("assets") && hash["assets"].is_a?(Hash) && hash["assets"].key?("asset")
|
||||
asset_content = hash["assets"].delete("asset")
|
||||
# Force the structure to be: [ {"asset" => asset_content} ]
|
||||
hash["assets"] = [ {"asset" => asset_content} ]
|
||||
end
|
||||
|
||||
hash
|
||||
end
|
||||
|
||||
# Converts an XML string into a corresponding Ruby Hash (JSON-like) structure.
|
||||
#
|
||||
# @param xmlstr [String] The XML string.
|
||||
# @return [Hash] The resulting Ruby hash structure.
|
||||
def self.xml2json(xmlstr)
|
||||
doc = REXML::Document.new(xmlstr)
|
||||
root_element = doc.root
|
||||
return {} unless root_element
|
||||
|
||||
# The final output is a hash containing the single root element and its content.
|
||||
{ root_element.name => xml2json_recursive(root_element) }
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue