1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include "model_helper.hxx"
24 #include "evaluationcontext.hxx"
25 #include "unohelper.hxx"
26 #include "submission/serialization_app_xml.hxx"
27 #include "resourcehelper.hxx"
28 #include "xmlhelper.hxx"
29 #include "convert.hxx"
30 #include <strings.hrc>
32 #include <rtl/ustring.hxx>
33 #include <rtl/ustrbuf.hxx>
34 #include <tools/debug.hxx>
35 #include <comphelper/processfactory.hxx>
38 #include <com/sun/star/xml/dom/XNode.hpp>
39 #include <com/sun/star/xml/dom/XDocumentBuilder.hpp>
40 #include <com/sun/star/xml/dom/XDocumentFragment.hpp>
41 #include <com/sun/star/xml/dom/XNamedNodeMap.hpp>
42 #include <com/sun/star/xml/xpath/XXPathObject.hpp>
43 #include <com/sun/star/xml/xpath/XPathObjectType.hpp>
44 #include <com/sun/star/beans/PropertyValue.hpp>
45 #include <com/sun/star/io/TextInputStream.hpp>
46 #include <com/sun/star/container/XEnumeration.hpp>
47 #include <com/sun/star/container/XNameContainer.hpp>
48 #include <com/sun/star/frame/XModel.hpp>
49 #include <com/sun/star/xforms/XFormsSupplier.hpp>
50 #include <com/sun/star/xforms/XDataTypeRepository.hpp>
51 #include <com/sun/star/xsd/XDataType.hpp>
52 #include <com/sun/star/xsd/DataTypeClass.hpp>
55 using com::sun::star::beans::PropertyValue
;
56 using com::sun::star::io::TextInputStream
;
57 using com::sun::star::io::XTextInputStream2
;
58 using com::sun::star::container::XEnumeration
;
59 using com::sun::star::container::XNameContainer
;
60 using com::sun::star::xforms::XFormsSupplier
;
62 using namespace xforms
;
63 using namespace com::sun::star::uno
;
64 using namespace com::sun::star::xml::dom
;
65 using namespace com::sun::star::xml::xpath
;
68 // implement XFormsUIHelper1
71 OUString
Model::getDefaultServiceNameForNode( const css::uno::Reference
<css::xml::dom::XNode
>& xNode
)
73 // determine service for control. string/text field is default.
74 OUString sService
= "com.sun.star.form.component.TextField";
76 // query repository for suitable type
77 OSL_ENSURE( mxDataTypes
.is(), "no type repository?" );
78 OUString sTypeName
= queryMIP( xNode
).getTypeName();
79 if( mxDataTypes
->hasByName( sTypeName
) )
81 OSL_ENSURE( mxDataTypes
->getDataType( sTypeName
).is(),
84 switch( mxDataTypes
->getDataType( sTypeName
)->getTypeClass() )
86 case css::xsd::DataTypeClass::BOOLEAN
:
87 sService
= "com.sun.star.form.component.CheckBox";
89 case css::xsd::DataTypeClass::DOUBLE
:
90 case css::xsd::DataTypeClass::DECIMAL
:
91 case css::xsd::DataTypeClass::FLOAT
:
92 sService
= "com.sun.star.form.component.NumericField";
95 case css::xsd::DataTypeClass::STRING
:
96 case css::xsd::DataTypeClass::DURATION
:
97 case css::xsd::DataTypeClass::DATETIME
:
98 case css::xsd::DataTypeClass::TIME
:
99 case css::xsd::DataTypeClass::DATE
:
100 case css::xsd::DataTypeClass::gYearMonth
:
101 case css::xsd::DataTypeClass::gYear
:
102 case css::xsd::DataTypeClass::gMonthDay
:
103 case css::xsd::DataTypeClass::gDay
:
104 case css::xsd::DataTypeClass::gMonth
:
105 case css::xsd::DataTypeClass::hexBinary
:
106 case css::xsd::DataTypeClass::base64Binary
:
107 case css::xsd::DataTypeClass::anyURI
:
108 case css::xsd::DataTypeClass::QName
:
109 case css::xsd::DataTypeClass::NOTATION
:
120 static void lcl_OutPosition( OUStringBuffer
& rBuffer
,
121 const Reference
<XNode
>& xNode
)
123 OSL_ENSURE( xNode
->getParentNode().is(), "need parent" );
125 // count # of occurrences of this node
126 sal_Int32 nFound
= 0;
127 sal_Int32 nPosition
= -1;
128 if( xNode
->getParentNode().is() )
130 for( Reference
<XNode
> xIter
= xNode
->getParentNode()->getFirstChild();
132 xIter
= xIter
->getNextSibling() )
134 if( xIter
->getNodeType() == xNode
->getNodeType() &&
135 xIter
->getNodeName() == xNode
->getNodeName() &&
136 xIter
->getNamespaceURI() == xNode
->getNamespaceURI() )
144 OSL_ENSURE( nFound
> 0 && nPosition
> 0, "node not found???" );
146 // output position (if necessary)
149 rBuffer
.insert( 0, ']' );
150 rBuffer
.insert( 0, nPosition
);
151 rBuffer
.insert( 0, '[' );
155 static void lcl_OutName( OUStringBuffer
& rBuffer
,
156 const Reference
<XNode
>& xNode
)
158 rBuffer
.insert( 0, xNode
->getNodeName() );
159 OUString sPrefix
= xNode
->getPrefix();
160 if( !sPrefix
.isEmpty() )
162 rBuffer
.insert( 0, sPrefix
+ ":" );
166 static void lcl_OutInstance( OUStringBuffer
& rBuffer
,
167 const Reference
<XNode
>& xNode
,
170 Reference
<XDocument
> xDoc
= xNode
->getOwnerDocument();
172 if( xDoc
== pModel
->getDefaultInstance() )
175 rBuffer
.insert( 0, "')" );
177 // iterate over instances, and find the right one
178 OUString sInstanceName
;
179 Reference
<XEnumeration
> xEnum
=
180 pModel
->getInstances()->createEnumeration();
181 while( sInstanceName
.isEmpty() && xEnum
->hasMoreElements() )
183 Sequence
<PropertyValue
> aValues
;
184 xEnum
->nextElement() >>= aValues
;
186 // get ID and instance
188 Reference
<XDocument
> xInstance
;
189 getInstanceData( aValues
, &sId
, &xInstance
, nullptr, nullptr );
191 // now check whether this was our instance:
192 if( xInstance
== xDoc
)
196 rBuffer
.insert( 0, "instance('" + sInstanceName
);
199 OUString
Model::getDefaultBindingExpressionForNode(
200 const XNode_t
& xNode
,
201 const EvaluationContext
& rContext
)
203 OSL_ENSURE( xNode
.is(), "need node" );
205 // iterate upwards and put sections into the expression buffer.
206 // Stop iteration either at context node (relative expression) or
207 // at document root, whichever occurs first.
208 OUStringBuffer aBuffer
;
209 for( Reference
<XNode
> xCurrent
= xNode
;
210 xCurrent
.is() && xCurrent
!= rContext
.mxContextNode
;
211 xCurrent
= xCurrent
->getParentNode() )
213 // insert a '/' for every step except the first
214 if( !aBuffer
.isEmpty() )
215 aBuffer
.insert( 0, '/' );
217 switch( xCurrent
->getNodeType() )
219 case NodeType_ELEMENT_NODE
:
220 lcl_OutPosition( aBuffer
, xCurrent
);
221 lcl_OutName( aBuffer
, xCurrent
);
224 case NodeType_TEXT_NODE
:
225 lcl_OutPosition( aBuffer
, xCurrent
);
226 aBuffer
.insert( 0, "text()" );
229 case NodeType_ATTRIBUTE_NODE
:
230 lcl_OutName( aBuffer
, xCurrent
);
231 aBuffer
.insert( 0, '@' );
234 case NodeType_DOCUMENT_NODE
:
235 // check for which instance we have
236 lcl_OutInstance( aBuffer
, xCurrent
, this );
240 // unknown type? fail!
241 OSL_FAIL( "unknown node type!" );
246 return aBuffer
.makeStringAndClear();
250 OUString
Model::getDefaultBindingExpressionForNode( const css::uno::Reference
<css::xml::dom::XNode
>& xNode
)
252 return getDefaultBindingExpressionForNode( xNode
, getEvaluationContext() );
255 static bool lcl_isWhitespace( const OUString
& rString
)
257 sal_Int32 nLength
= rString
.getLength();
258 const sal_Unicode
* pStr
= rString
.getStr();
260 bool bWhitespace
= true;
261 for( sal_Int32 i
= 0; bWhitespace
&& ( i
< nLength
); i
++ )
263 sal_Unicode c
= pStr
[i
];
264 bWhitespace
= ( c
== u
'\x0009' ||
272 OUString
Model::getNodeDisplayName( const css::uno::Reference
<css::xml::dom::XNode
>& xNode
,
275 OUStringBuffer aBuffer
;
277 switch( xNode
->getNodeType() )
279 case NodeType_ELEMENT_NODE
:
280 lcl_OutName( aBuffer
, xNode
);
283 case NodeType_TEXT_NODE
:
285 OUString sContent
= xNode
->getNodeValue();
286 if( bDetail
|| ! lcl_isWhitespace( sContent
) )
288 aBuffer
.append("\"" + Convert::collapseWhitespace( sContent
) + "\"");
293 case NodeType_ATTRIBUTE_NODE
:
294 lcl_OutName( aBuffer
, xNode
);
295 aBuffer
.insert( 0, '@' );
298 case NodeType_DOCUMENT_NODE
:
299 if( xNode
== getDefaultInstance() )
300 aBuffer
.append( '/' );
302 lcl_OutInstance( aBuffer
, xNode
, this );
306 // unknown type? fail!
307 OSL_FAIL( "unknown node type!" );
311 return aBuffer
.makeStringAndClear();
314 OUString
Model::getNodeName( const css::uno::Reference
<css::xml::dom::XNode
>& xNode
)
316 OUStringBuffer aBuffer
;
318 switch( xNode
->getNodeType() )
320 case NodeType_ELEMENT_NODE
:
321 case NodeType_ATTRIBUTE_NODE
:
322 lcl_OutName( aBuffer
, xNode
);
325 case NodeType_TEXT_NODE
:
326 case NodeType_DOCUMENT_NODE
:
328 // unknown type? fail!
329 OSL_FAIL( "no name for this node type!" );
333 return aBuffer
.makeStringAndClear();
336 OUString
Model::getBindingName( const css::uno::Reference
< ::css::beans::XPropertySet
>& xBinding
,
337 sal_Bool
/*bDetail*/ )
340 xBinding
->getPropertyValue( "BindingID" ) >>= sID
;
341 OUString sExpression
;
342 xBinding
->getPropertyValue( "BindingExpression" ) >>= sExpression
;
347 sRet
= sID
+ " (" + sExpression
+ ") ";
355 OUString
Model::getSubmissionName( const css::uno::Reference
< ::css::beans::XPropertySet
>& xSubmission
,
356 sal_Bool
/*bDetail*/ )
359 xSubmission
->getPropertyValue( "ID" ) >>= sID
;
363 css::uno::Reference
< ::css::beans::XPropertySet
> Model::cloneBindingAsGhost( const css::uno::Reference
< ::css::beans::XPropertySet
> &xBinding
)
365 // Create a new binding instance first...
366 rtl::Reference
<Binding
> pBinding
= new Binding();
368 // ...and bump up the "deferred notification counter"
369 // to prevent this binding from contributing to the
371 pBinding
->deferNotifications(true);
373 // Copy the propertyset and return result...
374 XPropertySet_t
xNewBinding(pBinding
);
375 copy( xBinding
, xNewBinding
);
379 void Model::removeBindingIfUseless( const css::uno::Reference
< ::css::beans::XPropertySet
>& xBinding
)
381 Binding
* pBinding
= comphelper::getFromUnoTunnel
<Binding
>( xBinding
);
382 if( pBinding
!= nullptr )
384 if( ! pBinding
->isUseful() )
385 mxBindings
->removeItem( pBinding
);
389 css::uno::Reference
<css::xml::dom::XDocument
> Model::newInstance( const OUString
& sName
,
390 const OUString
& sURL
,
393 // create a default instance with <instanceData> element
394 css::uno::Reference
<css::xml::dom::XDocument
> xInstance
= getDocumentBuilder()->newDocument();
395 DBG_ASSERT( xInstance
.is(), "failed to create DOM instance" );
397 Reference
<XNode
>( xInstance
, UNO_QUERY_THROW
)->appendChild(
398 Reference
<XNode
>( xInstance
->createElement( "instanceData" ),
401 Sequence
<PropertyValue
> aSequence
;
402 bool bOnce
= bURLOnce
; // bool, so we can take address in setInstanceData
403 setInstanceData( aSequence
, &sName
, &xInstance
, &sURL
, &bOnce
);
404 sal_Int32 nInstance
= mxInstances
->addItem( aSequence
);
405 loadInstance( nInstance
);
410 static sal_Int32
lcl_findProp( const PropertyValue
* pValues
,
412 std::u16string_view rName
)
416 for( ; !bFound
&& n
< nLength
; n
++ )
418 bFound
= ( pValues
[n
].Name
== rName
);
420 return bFound
? ( n
- 1) : -1;
423 sal_Int32
xforms::lcl_findInstance( const InstanceCollection
* pInstances
,
424 std::u16string_view rName
)
426 sal_Int32 nLength
= pInstances
->countItems();
429 for( ; !bFound
&& n
< nLength
; n
++ )
432 getInstanceData( pInstances
->getItem( n
), &sName
, nullptr, nullptr, nullptr );
433 bFound
= ( sName
== rName
);
435 return bFound
? ( n
- 1 ) : -1;
438 void Model::renameInstance( const OUString
& sFrom
,
440 const OUString
& sURL
,
443 sal_Int32 nPos
= lcl_findInstance( mxInstances
.get(), sFrom
);
447 Sequence
<PropertyValue
> aSeq
= mxInstances
->getItem( nPos
);
448 PropertyValue
* pSeq
= aSeq
.getArray();
449 sal_Int32 nLength
= aSeq
.getLength();
451 sal_Int32 nProp
= lcl_findProp( pSeq
, nLength
, u
"ID" );
455 aSeq
.realloc( nLength
+ 1 );
456 pSeq
= aSeq
.getArray();
457 pSeq
[ nLength
].Name
= "ID";
462 pSeq
[ nProp
].Value
<<= sTo
;
465 nProp
= lcl_findProp( pSeq
, nLength
, u
"URL" );
467 pSeq
[ nProp
].Value
<<= sURL
;
470 nProp
= lcl_findProp( pSeq
, nLength
, u
"URLOnce" );
472 pSeq
[ nProp
].Value
<<= bURLOnce
;
475 mxInstances
->setItem( nPos
, aSeq
);
478 void Model::removeInstance( const OUString
& sName
)
480 sal_Int32 nPos
= lcl_findInstance( mxInstances
.get(), sName
);
482 mxInstances
->removeItem( mxInstances
->getItem( nPos
) );
485 static Reference
<XNameContainer
> lcl_getModels(
486 const Reference
<css::frame::XModel
>& xComponent
)
488 Reference
<XNameContainer
> xRet
;
489 Reference
<XFormsSupplier
> xSupplier( xComponent
, UNO_QUERY
);
492 xRet
= xSupplier
->getXForms();
497 css::uno::Reference
<css::xforms::XModel
> Model::newModel( const Reference
<css::frame::XModel
>& xCmp
,
498 const OUString
& sName
)
500 css::uno::Reference
<css::xforms::XModel
> xModel
;
501 Reference
<XNameContainer
> xModels
= lcl_getModels( xCmp
);
503 && ! xModels
->hasByName( sName
) )
505 rtl::Reference
<Model
> pModel
= new Model();
506 xModel
.set( pModel
);
508 pModel
->setID( sName
);
509 pModel
->newInstance( OUString(), OUString(), false );
510 pModel
->initialize();
511 xModels
->insertByName( sName
, Any( xModel
) );
517 void Model::renameModel( const Reference
<css::frame::XModel
>& xCmp
,
518 const OUString
& sFrom
,
519 const OUString
& sTo
)
521 Reference
<XNameContainer
> xModels
= lcl_getModels( xCmp
);
523 && xModels
->hasByName( sFrom
)
524 && ! xModels
->hasByName( sTo
) )
526 Reference
<XModel
> xModel( xModels
->getByName( sFrom
), UNO_QUERY
);
527 xModel
->setID( sTo
);
528 xModels
->insertByName( sTo
, Any( xModel
) );
529 xModels
->removeByName( sFrom
);
533 void Model::removeModel( const Reference
<css::frame::XModel
>& xCmp
,
534 const OUString
& sName
)
536 Reference
<XNameContainer
> xModels
= lcl_getModels( xCmp
);
538 && xModels
->hasByName( sName
) )
540 xModels
->removeByName( sName
);
544 css::uno::Reference
<css::xml::dom::XNode
> Model::createElement( const css::uno::Reference
<css::xml::dom::XNode
>& xParent
,
545 const OUString
& sName
)
547 Reference
<XNode
> xNode
;
549 && isValidXMLName( sName
) )
551 // TODO: implement proper namespace handling
552 xNode
= xParent
->getOwnerDocument()->createElement( sName
);
557 css::uno::Reference
<css::xml::dom::XNode
> Model::createAttribute( const css::uno::Reference
<css::xml::dom::XNode
>& xParent
,
558 const OUString
& sName
)
560 Reference
<XNode
> xNode
;
561 Reference
<XElement
> xElement( xParent
, UNO_QUERY
);
564 && isValidXMLName( sName
) )
566 // handle case where attribute already exists
567 sal_Int32 nCount
= 0;
568 OUString sUniqueName
= sName
;
569 while( xElement
->hasAttribute( sUniqueName
) )
572 sUniqueName
= sName
+ OUString::number( nCount
);
575 // TODO: implement proper namespace handling
576 xNode
= xParent
->getOwnerDocument()->createAttribute( sUniqueName
);
581 css::uno::Reference
<css::xml::dom::XNode
> Model::renameNode( const css::uno::Reference
<css::xml::dom::XNode
>& xNode
,
582 const OUString
& sName
)
584 // early out if we don't have to change the name
585 if( xNode
->getNodeName() == sName
)
588 // refuse to change name if it's an attribute, and the name is already used
589 if( xNode
->getNodeType() == NodeType_ATTRIBUTE_NODE
590 && xNode
->getParentNode().is()
591 && Reference
<XElement
>(xNode
->getParentNode(), UNO_QUERY_THROW
)->hasAttribute( sName
) )
594 // note old binding expression so we can adjust bindings below
595 OUString sOldDefaultBindingExpression
=
596 getDefaultBindingExpressionForNode( xNode
);
598 Reference
<XDocument
> xDoc
= xNode
->getOwnerDocument();
599 Reference
<XNode
> xNew
;
600 if( xNode
->getNodeType() == NodeType_ELEMENT_NODE
)
602 Reference
<XElement
> xElem
= xDoc
->createElement( sName
);
605 // iterate over all attributes and append them to the new element
606 Reference
<XElement
> xOldElem( xNode
, UNO_QUERY
);
607 OSL_ENSURE( xNode
.is(), "no element?" );
609 Reference
<XNamedNodeMap
> xMap
= xNode
->getAttributes();
610 sal_Int32 nLength
= xMap
.is() ? xMap
->getLength() : 0;
611 // looping until nLength is suspicious wrt removeAttributeNode
612 // presumably shrinking XNamedNodeMap::getLength by 1
613 for( sal_Int32 n
= 0; n
< nLength
; n
++ )
615 Reference
<XAttr
> xAttr( xMap
->item(n
), UNO_QUERY
);
616 xElem
->setAttributeNode( xOldElem
->removeAttributeNode( xAttr
) );
619 // iterate over all children and append them to the new element
620 for( Reference
<XNode
> xCurrent
= xNode
->getFirstChild();
622 xCurrent
= xNode
->getFirstChild() )
624 xNew
->appendChild( xNode
->removeChild( xCurrent
) );
627 xNode
->getParentNode()->replaceChild( xNew
, xNode
);
629 else if( xNode
->getNodeType() == NodeType_ATTRIBUTE_NODE
)
631 // create new attribute
632 Reference
<XAttr
> xAttr
= xDoc
->createAttribute( sName
);
633 xAttr
->setValue( xNode
->getNodeValue() );
636 Reference
<XNode
> xParent
= xNode
->getParentNode();
637 xParent
->removeChild( xNode
);
638 xNew
= xParent
->appendChild( xAttr
);
642 OSL_FAIL( "can't rename this node type" );
645 // adjust bindings (if necessary):
648 // iterate over bindings and replace default expressions
649 OUString sNewDefaultBindingExpression
=
650 getDefaultBindingExpressionForNode( xNew
);
651 for( sal_Int32 n
= 0; n
< mxBindings
->countItems(); n
++ )
653 Binding
* pBinding
= comphelper::getFromUnoTunnel
<Binding
>(
654 mxBindings
->Collection
<XPropertySet_t
>::getItem( n
) );
656 if( pBinding
->getBindingExpression()
657 == sOldDefaultBindingExpression
)
658 pBinding
->setBindingExpression( sNewDefaultBindingExpression
);
662 // return node; return old node if renaming failed
663 return xNew
.is() ? xNew
: xNode
;
666 css::uno::Reference
< ::css::beans::XPropertySet
> Model::getBindingForNode( const css::uno::Reference
<css::xml::dom::XNode
>& xNode
,
669 OSL_ENSURE( xNode
.is(), "no node?" );
671 // We will iterate over all bindings and determine the
672 // appropriateness of the respective binding for this node. The
673 // best one will be used. If we don't find any and bCreate is set,
674 // then we will create a suitable binding.
675 rtl::Reference
<Binding
> pBestBinding
;
676 sal_Int32 nBestScore
= 0;
678 for( sal_Int32 n
= 0; n
< mxBindings
->countItems(); n
++ )
680 Binding
* pBinding
= comphelper::getFromUnoTunnel
<Binding
>(
681 mxBindings
->Collection
<XPropertySet_t
>::getItem( n
) );
683 OSL_ENSURE( pBinding
!= nullptr, "no binding?" );
684 Reference
<XNodeList
> xNodeList
= pBinding
->getXNodeList();
686 sal_Int32 nNodes
= xNodeList
.is() ? xNodeList
->getLength() : 0;
687 if( nNodes
> 0 && xNodeList
->item( 0 ) == xNode
)
689 // allright, we found a suitable node. Let's determine how
690 // well it fits. Score:
691 // - bind to exactly this node is better than whole nodeset
692 // - simple binding expressions is better than complex ones
693 sal_Int32 nScore
= 0;
696 if( pBinding
->isSimpleBindingExpression() )
699 // if we found a better binding, remember it
700 if( nScore
> nBestScore
)
702 pBestBinding
= pBinding
;
708 // create binding, if none was found and bCreate is set
709 OSL_ENSURE( ( nBestScore
== 0 ) == ( pBestBinding
== nullptr ),
710 "score != binding?" );
711 if( bCreate
&& pBestBinding
== nullptr )
713 pBestBinding
= new Binding();
714 pBestBinding
->setBindingExpression(
715 getDefaultBindingExpressionForNode( xNode
) );
716 mxBindings
->addItem( pBestBinding
);
722 void Model::removeBindingForNode( const css::uno::Reference
<css::xml::dom::XNode
>& )
724 // determine whether suitable binding is still used
727 static OUString
lcl_serializeForDisplay( const Reference
< XAttr
>& _rxAttrNode
)
730 OSL_ENSURE( _rxAttrNode
.is(), "lcl_serializeForDisplay( attr ): invalid argument!" );
731 if ( _rxAttrNode
.is() )
733 OUString sValue
= _rxAttrNode
->getValue();
734 sal_Unicode nQuote
= '"';
735 if ( sValue
.indexOf( nQuote
) >= 0 )
738 sResult
= _rxAttrNode
->getName() + "=" + OUStringChar(nQuote
) + sValue
+ OUStringChar(nQuote
) + " ";
743 static OUString
lcl_serializeForDisplay( const Reference
<XNodeList
>& xNodes
)
745 OUStringBuffer sResult
;
747 // create document fragment
748 Reference
<XDocument
> xDocument( getDocumentBuilder()->newDocument() );
749 Reference
<XDocumentFragment
> xFragment(
750 xDocument
->createDocumentFragment() );
751 OSL_ENSURE( xFragment
.is(), "xFragment" );
753 sal_Int32 nAttributeNodes
= 0;
755 // attach nodelist to fragment
756 sal_Int32 nLength
= xNodes
->getLength();
757 for( sal_Int32 i
= 0; i
< nLength
; i
++ )
759 Reference
<XNode
> xCurrent
= xNodes
->item( i
);
761 switch ( xCurrent
->getNodeType() )
763 case NodeType_DOCUMENT_NODE
:
764 // special-case documents: use top-level element instead
765 xCurrent
= xCurrent
->getFirstChild();
767 case NodeType_ATTRIBUTE_NODE
:
769 Reference
< XAttr
> xAttr( xCurrent
, UNO_QUERY
);
772 sResult
.append(lcl_serializeForDisplay( xAttr
));
783 xFragment
->appendChild( xDocument
->importNode( xCurrent
, true ) );
785 OSL_ENSURE( ( nAttributeNodes
== 0 ) || ( nAttributeNodes
== nLength
),
786 "lcl_serializeForDisplay: mixed attribute and non-attribute nodes?" );
787 if ( nAttributeNodes
)
788 // had only attribute nodes
789 return sResult
.makeStringAndClear();
791 // serialize fragment
792 CSerializationAppXML aSerialization
;
793 aSerialization
.setSource( xFragment
);
794 aSerialization
.serialize();
796 // copy stream into buffer
797 Reference
<XTextInputStream2
> xTextInputStream
= TextInputStream::create( comphelper::getProcessComponentContext() );
798 xTextInputStream
->setInputStream( aSerialization
.getInputStream() );
800 /* WORK AROUND for problem in serialization: currently, multiple
801 XML declarations (<?xml...?>) are being written out and we don't
802 want them. When this is fixed, the code below is nice and
803 simple. The current code filters out the declarations.
804 OUString sResult = xTextInputStream->readString( Sequence<sal_Unicode>(),
808 // well, the serialization prepends XML header(s) that we need to
810 sResult
.setLength(0);
811 while( ! xTextInputStream
->isEOF() )
813 OUString sLine
= xTextInputStream
->readLine();
815 && !sLine
.startsWith( "<?xml" ) )
817 sResult
.append( sLine
+ "\n" );
821 return sResult
.makeStringAndClear();
824 static OUString
lcl_serializeForDisplay( const Reference
<XXPathObject
>& xResult
)
826 // error handling first
828 return getResource( RID_STR_XFORMS_CANT_EVALUATE
);
831 switch( xResult
->getObjectType() )
833 case XPathObjectType_XPATH_BOOLEAN
:
834 return OUString::boolean(xResult
->getBoolean());
836 case XPathObjectType_XPATH_STRING
:
837 return "\"" + xResult
->getString() + "\"";
839 case XPathObjectType_XPATH_NODESET
:
840 return lcl_serializeForDisplay( xResult
->getNodeList() );
842 case XPathObjectType_XPATH_NUMBER
:
843 return OUString::number(xResult
->getDouble());
845 case XPathObjectType_XPATH_UNDEFINED
:
846 case XPathObjectType_XPATH_POINT
:
847 case XPathObjectType_XPATH_RANGE
:
848 case XPathObjectType_XPATH_LOCATIONSET
:
849 case XPathObjectType_XPATH_USERS
:
850 case XPathObjectType_XPATH_XSLT_TREE
:
852 // TODO: localized error message?
857 OUString
Model::getResultForExpression(
858 const css::uno::Reference
< ::css::beans::XPropertySet
>& xBinding
,
859 sal_Bool bIsBindingExpression
,
860 const OUString
& sExpression
)
862 Binding
* pBinding
= comphelper::getFromUnoTunnel
<Binding
>( xBinding
);
863 if( pBinding
== nullptr )
864 throw RuntimeException();
866 // prepare & evaluate expression
867 OUStringBuffer aBuffer
;
868 ComputedExpression aExpression
;
869 aExpression
.setExpression( sExpression
);
870 if( bIsBindingExpression
)
872 // binding: use binding context and evaluation
873 aExpression
.evaluate( pBinding
->getEvaluationContext() );
874 aBuffer
.append( lcl_serializeForDisplay( aExpression
.getXPath() ) );
878 // MIP (not binding): iterate over bindings contexts
879 std::vector
<EvaluationContext
> aContext
=
880 pBinding
->getMIPEvaluationContexts();
881 for (auto const& elem
: aContext
)
883 aExpression
.evaluate(elem
);
884 aBuffer
.append( lcl_serializeForDisplay(aExpression
.getXPath()) );
885 aBuffer
.append( '\n' );
888 return aBuffer
.makeStringAndClear();
891 sal_Bool
Model::isValidXMLName( const OUString
& sName
)
893 return isValidQName( sName
, nullptr );
896 sal_Bool
Model::isValidPrefixName( const OUString
& sName
)
898 return ::isValidPrefixName( sName
, nullptr );
901 void Model::setNodeValue(
902 const css::uno::Reference
< ::css::xml::dom::XNode
>& xNode
,
903 const OUString
& sValue
)
905 setSimpleContent( xNode
, sValue
);
909 // helper functions from model_helper.hxx
912 void xforms::getInstanceData(
913 const Sequence
<PropertyValue
>& aValues
,
915 Reference
<XDocument
>* pInstance
,
919 sal_Int32 nValues
= aValues
.getLength();
920 const PropertyValue
* pValues
= aValues
.getConstArray();
921 for( sal_Int32 n
= 0; n
< nValues
; n
++ )
923 const PropertyValue
& rValue
= pValues
[n
];
924 if( pID
!= nullptr && rValue
.Name
== "ID")
925 rValue
.Value
>>= *pID
;
926 if( pInstance
!= nullptr && rValue
.Name
== "Instance")
927 rValue
.Value
>>= *pInstance
;
928 if( pURL
!= nullptr && rValue
.Name
== "URL")
929 rValue
.Value
>>= *pURL
;
930 if( pURLOnce
!= nullptr && rValue
.Name
== "URLOnce")
931 rValue
.Value
>>= *pURLOnce
;
935 void xforms::setInstanceData(
936 Sequence
<PropertyValue
>& aSequence
,
937 const OUString
* _pID
,
938 const Reference
<XDocument
>* _pInstance
,
939 const OUString
* _pURL
,
940 const bool* _pURLOnce
)
942 // get old instance data
944 Reference
<XDocument
> xInstance
;
946 bool bURLOnce
= false;
947 getInstanceData( aSequence
, &sID
, &xInstance
, &sURL
, &bURLOnce
);
948 const OUString
* pID
= !sID
.isEmpty() ? &sID
: nullptr;
949 const Reference
<XDocument
>* pInstance
= xInstance
.is() ? &xInstance
: nullptr;
950 const OUString
* pURL
= !sURL
.isEmpty() ? &sURL
: nullptr;
951 const bool* pURLOnce
= ( bURLOnce
&& pURL
!= nullptr ) ? &bURLOnce
: nullptr;
953 // determine new instance data
956 if (_pInstance
!= nullptr)
957 pInstance
= _pInstance
;
958 if (_pURL
!= nullptr)
960 if (_pURLOnce
!= nullptr)
961 pURLOnce
= _pURLOnce
;
963 // count # of values we want to set
964 sal_Int32 nCount
= 0;
967 if (pInstance
!= nullptr)
971 if (pURLOnce
!= nullptr)
974 // realloc sequence and enter values;
975 aSequence
.realloc( nCount
);
976 PropertyValue
* pSequence
= aSequence
.getArray();
977 sal_Int32 nIndex
= 0;
980 pSequence
[ nIndex
].Name
= "ID";
981 pSequence
[ nIndex
].Value
<<= *pID
;
984 if(pInstance
!= nullptr)
986 pSequence
[ nIndex
].Name
= "Instance";
987 pSequence
[ nIndex
].Value
<<= *pInstance
;
992 pSequence
[ nIndex
].Name
= "URL";
993 pSequence
[ nIndex
].Value
<<= *pURL
;
996 if(pURLOnce
!= nullptr)
998 pSequence
[ nIndex
].Name
= "URLOnce";
999 pSequence
[ nIndex
].Value
<<= *pURLOnce
;
1004 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */