1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 #include "precompiled_xmloff.hxx" 25 26 #include "RDFaExportHelper.hxx" 27 28 #include "xmloff/xmlnmspe.hxx" 29 30 #include <xmloff/xmlexp.hxx> 31 #include <xmloff/xmltoken.hxx> 32 33 #include <comphelper/stlunosequence.hxx> 34 #include <comphelper/stl_types.hxx> 35 36 #include <com/sun/star/uri/XUriReference.hpp> 37 #include <com/sun/star/uri/XUriReferenceFactory.hpp> 38 #include <com/sun/star/rdf/Statement.hpp> 39 #include <com/sun/star/rdf/URIs.hpp> 40 #include <com/sun/star/rdf/URI.hpp> 41 #include <com/sun/star/rdf/XLiteral.hpp> 42 #include <com/sun/star/rdf/XRepositorySupplier.hpp> 43 #include <com/sun/star/rdf/XDocumentRepository.hpp> 44 45 #include <rtl/ustrbuf.hxx> 46 47 #include <boost/bind.hpp> 48 #include <boost/iterator_adaptors.hpp> 49 #ifndef BOOST_ITERATOR_ADAPTOR_DWA053000_HPP_ // from iterator_adaptors.hpp 50 // N.B.: the check for the header guard _of a specific version of boost_ 51 // is here so this may work on different versions of boost, 52 // which sadly put the goods in different header files 53 #include <boost/iterator/transform_iterator.hpp> 54 #endif 55 56 #include <functional> 57 #include <algorithm> 58 59 60 using namespace ::com::sun::star; 61 62 namespace xmloff { 63 64 static const char s_prefix [] = "_:b"; 65 66 static ::rtl::OUString 67 makeCURIE(SvXMLExport * i_pExport, 68 uno::Reference<rdf::XURI> const & i_xURI) 69 { 70 OSL_ENSURE(i_xURI.is(), "makeCURIE: null URI"); 71 if (!i_xURI.is()) throw uno::RuntimeException(); 72 73 const ::rtl::OUString Namespace( i_xURI->getNamespace() ); 74 OSL_ENSURE(Namespace.getLength(), "makeCURIE: no namespace"); 75 if (!Namespace.getLength()) throw uno::RuntimeException(); 76 77 ::rtl::OUStringBuffer buf; 78 buf.append( i_pExport->EnsureNamespace(Namespace) ); 79 buf.append( static_cast<sal_Unicode>(':') ); 80 // N.B.: empty LocalName is valid! 81 buf.append( i_xURI->getLocalName() ); 82 83 return buf.makeStringAndClear(); 84 } 85 86 // #i112473# SvXMLExport::GetRelativeReference() not right for RDF on SaveAs 87 // because the URIs in the repository are not rewritten on SaveAs, the 88 // URI of the loaded document has to be used, not the URI of the target doc. 89 static ::rtl::OUString 90 getRelativeReference(SvXMLExport const& rExport, ::rtl::OUString const& rURI) 91 { 92 uno::Reference< rdf::XURI > const xModelURI( 93 rExport.GetModel(), uno::UNO_QUERY_THROW ); 94 ::rtl::OUString const baseURI( xModelURI->getStringValue() ); 95 96 uno::Reference<uno::XComponentContext> const xContext( 97 rExport.GetComponentContext()); 98 uno::Reference<lang::XMultiComponentFactory> const xServiceFactory( 99 xContext->getServiceManager(), uno::UNO_SET_THROW); 100 uno::Reference<uri::XUriReferenceFactory> const xUriFactory( 101 xServiceFactory->createInstanceWithContext( 102 ::rtl::OUString::createFromAscii( 103 "com.sun.star.uri.UriReferenceFactory"), xContext), 104 uno::UNO_QUERY_THROW); 105 106 uno::Reference< uri::XUriReference > const xBaseURI( 107 xUriFactory->parse(baseURI), uno::UNO_SET_THROW ); 108 uno::Reference< uri::XUriReference > const xAbsoluteURI( 109 xUriFactory->parse(rURI), uno::UNO_SET_THROW ); 110 uno::Reference< uri::XUriReference > const xRelativeURI( 111 xUriFactory->makeRelative(xBaseURI, xAbsoluteURI, true, true, false), 112 uno::UNO_SET_THROW ); 113 ::rtl::OUString const relativeURI(xRelativeURI->getUriReference()); 114 115 return relativeURI; 116 } 117 118 119 //////////////////////////////////////////////////////////////////////////// 120 121 RDFaExportHelper::RDFaExportHelper(SvXMLExport & i_rExport) 122 : m_rExport(i_rExport), m_xRepository(0), m_Counter(0) 123 { 124 const uno::Reference<rdf::XRepositorySupplier> xRS( m_rExport.GetModel(), 125 uno::UNO_QUERY); 126 OSL_ENSURE(xRS.is(), "AddRDFa: model is no rdf::XRepositorySupplier"); 127 if (!xRS.is()) throw uno::RuntimeException(); 128 m_xRepository.set(xRS->getRDFRepository(), uno::UNO_QUERY_THROW); 129 } 130 131 ::rtl::OUString 132 RDFaExportHelper::LookupBlankNode( 133 uno::Reference<rdf::XBlankNode> const & i_xBlankNode) 134 { 135 OSL_ENSURE(i_xBlankNode.is(), "null BlankNode?"); 136 if (!i_xBlankNode.is()) throw uno::RuntimeException(); 137 ::rtl::OUString & rEntry( 138 m_BlankNodeMap[ i_xBlankNode->getStringValue() ] ); 139 if (!rEntry.getLength()) 140 { 141 ::rtl::OUStringBuffer buf; 142 buf.appendAscii(s_prefix); 143 buf.append(++m_Counter); 144 rEntry = buf.makeStringAndClear(); 145 } 146 return rEntry; 147 } 148 149 //////////////////////////////////////////////////////////////////////////// 150 151 void 152 RDFaExportHelper::AddRDFa( 153 uno::Reference<rdf::XMetadatable> const & i_xMetadatable) 154 { 155 try 156 { 157 beans::Pair< uno::Sequence<rdf::Statement>, sal_Bool > const 158 RDFaResult( m_xRepository->getStatementRDFa(i_xMetadatable) ); 159 160 uno::Sequence<rdf::Statement> const & rStatements( RDFaResult.First ); 161 162 if (0 == rStatements.getLength()) 163 { 164 return; // no RDFa 165 } 166 167 // all stmts have the same subject, so we only handle first one 168 const uno::Reference<rdf::XURI> xSubjectURI(rStatements[0].Subject, 169 uno::UNO_QUERY); 170 const uno::Reference<rdf::XBlankNode> xSubjectBNode( 171 rStatements[0].Subject, uno::UNO_QUERY); 172 if (!xSubjectURI.is() && !xSubjectBNode.is()) 173 { 174 throw uno::RuntimeException(); 175 } 176 static const sal_Unicode s_OpenBracket ('['); 177 static const sal_Unicode s_CloseBracket(']'); 178 const ::rtl::OUString about( xSubjectURI.is() 179 ? getRelativeReference(m_rExport, xSubjectURI->getStringValue()) 180 : ::rtl::OUStringBuffer().append(s_OpenBracket).append( 181 LookupBlankNode(xSubjectBNode)).append(s_CloseBracket) 182 .makeStringAndClear() 183 ); 184 185 const uno::Reference<rdf::XLiteral> xContent( 186 rStatements[0].Object, uno::UNO_QUERY_THROW ); 187 const uno::Reference<rdf::XURI> xDatatype(xContent->getDatatype()); 188 if (xDatatype.is()) 189 { 190 const ::rtl::OUString datatype( 191 makeCURIE(&m_rExport, xDatatype) ); 192 m_rExport.AddAttribute(XML_NAMESPACE_XHTML, 193 token::XML_DATATYPE, datatype); 194 } 195 if (RDFaResult.Second) // there is xhtml:content 196 { 197 m_rExport.AddAttribute(XML_NAMESPACE_XHTML, token::XML_CONTENT, 198 xContent->getValue()); 199 } 200 201 ::rtl::OUStringBuffer property; 202 ::comphelper::intersperse( 203 ::boost::make_transform_iterator( 204 ::comphelper::stl_begin(rStatements), 205 ::boost::bind(&makeCURIE, &m_rExport, 206 ::boost::bind(&rdf::Statement::Predicate, _1))), 207 // argh, this must be the same type :( 208 ::boost::make_transform_iterator( 209 ::comphelper::stl_end(rStatements), 210 ::boost::bind(&makeCURIE, &m_rExport, 211 ::boost::bind(&rdf::Statement::Predicate, _1))), 212 ::comphelper::OUStringBufferAppender(property), 213 ::rtl::OUString::createFromAscii(" ")); 214 215 m_rExport.AddAttribute(XML_NAMESPACE_XHTML, token::XML_PROPERTY, 216 property.makeStringAndClear()); 217 218 m_rExport.AddAttribute(XML_NAMESPACE_XHTML, token::XML_ABOUT, about); 219 } 220 catch (uno::Exception &) 221 { 222 OSL_ENSURE(false, "AddRDFa: exception"); 223 } 224 } 225 226 } // namespace xmloff 227 228